From cea3a8e7e8cbf45f709ec63a096cf07b92c87073 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Thu, 29 May 2014 16:58:40 +0100 Subject: Cauldrons fill --- src/Blocks/BlockCauldron.h | 14 ++++++++++++++ src/Blocks/WorldInterface.h | 3 +++ src/Chunk.cpp | 1 - src/World.h | 4 ++-- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Blocks/BlockCauldron.h b/src/Blocks/BlockCauldron.h index 41b79b6c3..8b5cd9ccb 100644 --- a/src/Blocks/BlockCauldron.h +++ b/src/Blocks/BlockCauldron.h @@ -58,6 +58,20 @@ public: { return true; } + + virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + { + if (!a_WorldInterface.IsWeatherWet()) + { + return; + } + + NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); + if (Meta < 3) + { + a_Chunk.SetMeta(a_RelX, a_RelY, a_RelZ, Meta + 1); + } + } } ; diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h index bfbb053d9..08600d502 100644 --- a/src/Blocks/WorldInterface.h +++ b/src/Blocks/WorldInterface.h @@ -37,4 +37,7 @@ public: virtual void SetTimeOfDay(Int64 a_TimeOfDay) = 0; + /** Returns true if the current weather has any precipitation - rain or storm */ + virtual bool IsWeatherWet(void) const = 0; + }; diff --git a/src/Chunk.cpp b/src/Chunk.cpp index ca536e89a..4506cfcc5 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -961,7 +961,6 @@ void cChunk::ApplyWeatherToTop() } break; } // case (snowy biomes) - // TODO: Rainy biomes should check for farmland and cauldrons default: { break; diff --git a/src/World.h b/src/World.h index 86cbb3e7e..067e18547 100644 --- a/src/World.h +++ b/src/World.h @@ -690,8 +690,8 @@ public: bool IsWeatherStorm(void) const { return (m_Weather == wStorm); } /** Returns true if the current weather has any precipitation - rain or storm */ - bool IsWeatherWet (void) const { return (m_Weather != wSunny); } - + virtual bool IsWeatherWet(void) const override { return (m_Weather != wSunny); } + // tolua_end cChunkGenerator & GetGenerator(void) { return m_Generator; } -- cgit v1.2.3 From 60a37c1370dc766c55a344090d8d26bc2e1c1c99 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Thu, 29 May 2014 16:58:55 +0100 Subject: Very minor code changes --- src/Blocks/BlockBed.cpp | 2 +- src/Blocks/BlockPortal.h | 2 +- src/Mobs/Monster.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp index 6a3c6a55b..07ef997dd 100644 --- a/src/Blocks/BlockBed.cpp +++ b/src/Blocks/BlockBed.cpp @@ -108,7 +108,7 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); if (Meta & 0x4) { - a_Player->SendMessageFailure("This bed is occupied."); + a_Player->SendMessageFailure("This bed is occupied"); } else { diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h index 3b8030028..e718d9a70 100644 --- a/src/Blocks/BlockPortal.h +++ b/src/Blocks/BlockPortal.h @@ -55,7 +55,7 @@ public: virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - if ((a_RelY - 1 < 0) || (a_RelY + 1 > cChunkDef::Height)) + if ((a_RelY == 0) || (a_RelY == cChunkDef::Height)) // Y can't be < 0 or > Height; (Fast)SetBlock won't allow it { return false; // In case someone places a portal with meta 1 or 2 at boundaries, and server tries to get invalid coords at Y - 1 or Y + 1 } diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index a9ca7a2fa..839d21314 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -1024,7 +1024,7 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk) (a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand (GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime !IsOnFire() && // Not already burning - (GetWorld()->GetWeather() != eWeather_Rain) // Not raining + (GetWorld()->IsWeatherWet()) // Not raining ) { // Burn for 100 ticks, then decide again -- cgit v1.2.3 From 8bff3e5af220070ecc789ef551c0b8428b8953ef Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 31 May 2014 22:28:51 +0100 Subject: Implemented end and nether portals --- src/Chunk.cpp | 74 +++++++++++---------- src/Chunk.h | 1 + src/ClientHandle.cpp | 7 +- src/ClientHandle.h | 2 +- src/Entities/Entity.cpp | 117 +++++++++++++++++++++++++++++++++ src/Entities/Entity.h | 6 ++ src/Entities/Player.cpp | 36 +++++++--- src/Entities/Player.h | 2 +- src/Generating/BioGen.cpp | 2 +- src/Generating/ComposableGenerator.cpp | 16 +---- src/Generating/EndGen.cpp | 2 +- src/Generating/EndGen.h | 3 +- src/Protocol/Protocol.h | 2 +- src/Protocol/Protocol125.cpp | 4 +- src/Protocol/Protocol125.h | 2 +- src/Protocol/Protocol16x.cpp | 4 +- src/Protocol/Protocol16x.h | 2 +- src/Protocol/Protocol17x.cpp | 4 +- src/Protocol/Protocol17x.h | 2 +- src/Protocol/ProtocolRecognizer.cpp | 4 +- src/Protocol/ProtocolRecognizer.h | 2 +- src/Root.cpp | 21 +++--- src/World.cpp | 31 +++++++++ 23 files changed, 254 insertions(+), 92 deletions(-) diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 4506cfcc5..7131a26af 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -638,30 +638,22 @@ void cChunk::Tick(float a_Dt) for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) { // Mobs are tickes inside MobTick (as we don't have to tick them if they are far away from players) - if (!((*itr)->IsMob())) + // Don't tick things queued to be removed + if (!((*itr)->IsMob()) && (std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), (*itr)->GetUniqueID()) == m_EntitiesToRemove.end())) { (*itr)->Tick(a_Dt, *this); } } // for itr - m_Entitites[] - // Remove all entities that were scheduled for removal: for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) { - if ((*itr)->IsDestroyed()) - { - LOGD("Destroying entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass()); - cEntity * ToDelete = *itr; - itr = m_Entities.erase(itr); - delete ToDelete; - continue; - } - ++itr; - } // for itr - m_Entitites[] - - // If any entity moved out of the chunk, move it to the neighbor: - for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) - { - if ( + auto itr2 = std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), (*itr)->GetUniqueID()); + if (itr2 != m_EntitiesToRemove.end()) + { + itr = m_Entities.erase(itr); + m_EntitiesToRemove.erase(itr2); + } + else if ( // If any entity moved out of the chunk, move it to the neighbor: ((*itr)->GetChunkX() != m_PosX) || ((*itr)->GetChunkZ() != m_PosZ) ) @@ -671,9 +663,19 @@ void cChunk::Tick(float a_Dt) } else { - ++itr; + if ((*itr)->IsDestroyed()) // Remove all entities that were scheduled for removal: + { + LOGD("Destroying entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass()); + cEntity * ToDelete = *itr; + itr = m_Entities.erase(itr); + delete ToDelete; + } + else + { + ++itr; + } } - } + } // for itr - m_Entitites[] ApplyWeatherToTop(); } @@ -1847,7 +1849,7 @@ void cChunk::RemoveBlockEntity( cBlockEntity* a_BlockEntity ) -bool cChunk::AddClient(cClientHandle* a_Client) +bool cChunk::AddClient(cClientHandle * a_Client) { for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr) { @@ -1878,7 +1880,7 @@ bool cChunk::AddClient(cClientHandle* a_Client) -void cChunk::RemoveClient( cClientHandle* a_Client ) +void cChunk::RemoveClient(cClientHandle * a_Client) { for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr) { @@ -1886,12 +1888,12 @@ void cChunk::RemoveClient( cClientHandle* a_Client ) { continue; } - + m_LoadedByClient.erase(itr); if (!a_Client->IsDestroyed()) { - for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr ) + for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) { /* // DEBUG: @@ -1911,7 +1913,7 @@ void cChunk::RemoveClient( cClientHandle* a_Client ) -bool cChunk::HasClient( cClientHandle* a_Client ) +bool cChunk::HasClient(cClientHandle* a_Client) { for (cClientHandleList::const_iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr) { @@ -1942,9 +1944,9 @@ void cChunk::AddEntity(cEntity * a_Entity) { MarkDirty(); } - + ASSERT(std::find(m_Entities.begin(), m_Entities.end(), a_Entity) == m_Entities.end()); // Not there already - + m_Entities.push_back(a_Entity); } @@ -1954,17 +1956,12 @@ void cChunk::AddEntity(cEntity * a_Entity) void cChunk::RemoveEntity(cEntity * a_Entity) { - size_t SizeBefore = m_Entities.size(); - m_Entities.remove(a_Entity); - size_t SizeAfter = m_Entities.size(); - - if (SizeBefore != SizeAfter) + m_EntitiesToRemove.push_back(a_Entity->GetUniqueID()); + + // Mark as dirty if it was a server-generated entity: + if (!a_Entity->IsPlayer()) { - // Mark as dirty if it was a server-generated entity: - if (!a_Entity->IsPlayer()) - { - MarkDirty(); - } + MarkDirty(); } } @@ -1974,6 +1971,11 @@ void cChunk::RemoveEntity(cEntity * a_Entity) bool cChunk::HasEntity(int a_EntityID) { + if (std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), a_EntityID) != m_EntitiesToRemove.end()) + { + return false; // If EntitiesToRemove contains our ID, this chunk doesn't have it, as it should be removed soon + } + for (cEntityList::const_iterator itr = m_Entities.begin(), end = m_Entities.end(); itr != end; ++itr) { if ((*itr)->GetUniqueID() == a_EntityID) diff --git a/src/Chunk.h b/src/Chunk.h index 84ec35496..f61520e8f 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -411,6 +411,7 @@ private: // A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers cClientHandleList m_LoadedByClient; cEntityList m_Entities; + std::vector m_EntitiesToRemove; cBlockEntityList m_BlockEntities; /** Number of times the chunk has been requested to stay (by various cChunkStay objects); if zero, the chunk can be unloaded */ diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 9b03bead9..8a5c81e70 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -125,7 +125,6 @@ cClientHandle::~cClientHandle() } if (World != NULL) { - World->RemovePlayer(m_Player); m_Player->Destroy(); } delete m_Player; @@ -1754,7 +1753,7 @@ void cClientHandle::MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket) if (a_SendRespawnPacket) { - SendRespawn(); + SendRespawn(a_World); } cWorld * World = m_Player->GetWorld(); @@ -2373,9 +2372,9 @@ void cClientHandle::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effec -void cClientHandle::SendRespawn(void) +void cClientHandle::SendRespawn(const cWorld & a_World) { - m_Protocol->SendRespawn(); + m_Protocol->SendRespawn(a_World); } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 659c67658..e86287735 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -149,7 +149,7 @@ public: void SendPlayerSpawn (const cPlayer & a_Player); void SendPluginMessage (const AString & a_Channel, const AString & a_Message); // Exported in ManualBindings.cpp void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID); - void SendRespawn (void); + void SendRespawn (const cWorld & a_World); void SendExperience (void); void SendExperienceOrb (const cExpOrb & a_ExpOrb); void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode); diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 1226a2319..b5c272cf2 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -629,6 +629,7 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk) // Handle drowning HandleAir(); } + DetectPortal(); // None of the above functions change position, we remain in the chunk of NextChunk HandlePhysics(a_Dt, *NextChunk); @@ -1039,6 +1040,122 @@ void cEntity::DetectCacti(void) +void cEntity::DetectPortal() +{ + int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT; + if ((Y > 0) && (Y < cChunkDef::Height)) + { + switch (GetWorld()->GetBlock(X, Y, Z)) + { + case E_BLOCK_NETHER_PORTAL: + { + switch (GetWorld()->GetDimension()) + { + case dimNether: + { + AString OverworldName = GetWorld()->GetName().substr(0, GetWorld()->GetName().size() - 7); + cFile::CreateFolder(FILE_IO_PREFIX + OverworldName); + cIniFile File; + File.ReadFile(OverworldName + "/world.ini"); + File.SetValue("General", "Dimension", "Overworld"); + File.WriteFile(OverworldName + "/world.ini"); + + MoveToWorld(OverworldName, cRoot::Get()->CreateAndInitializeWorld(OverworldName)); + break; + } + case dimOverworld: + { + AString NetherWorldName = GetWorld()->GetName() + "_nether"; + cFile::CreateFolder(FILE_IO_PREFIX + NetherWorldName); + cIniFile File; + File.ReadFile(NetherWorldName + "/world.ini"); + File.SetValue("General", "Dimension", "Nether"); + File.WriteFile(NetherWorldName + "/world.ini"); + + MoveToWorld(NetherWorldName, cRoot::Get()->CreateAndInitializeWorld(NetherWorldName)); + break; + } + default: break; + } + break; + } + case E_BLOCK_END_PORTAL: + { + switch (GetWorld()->GetDimension()) + { + case dimEnd: + { + AString OverworldName = GetWorld()->GetName().substr(0, GetWorld()->GetName().size() - 4); + cFile::CreateFolder(FILE_IO_PREFIX + OverworldName); + cIniFile File; + File.ReadFile(OverworldName + "/world.ini"); + File.SetValue("General", "Dimension", "Overworld"); + File.WriteFile(OverworldName + "/world.ini"); + + MoveToWorld(OverworldName, cRoot::Get()->CreateAndInitializeWorld(OverworldName)); + break; + } + case dimOverworld: + { + AString EndWorldName = GetWorld()->GetName() + "_end"; + cFile::CreateFolder(FILE_IO_PREFIX + EndWorldName); + cIniFile File; + File.ReadFile(EndWorldName + "/world.ini"); + File.SetValue("General", "Dimension", "End"); + File.WriteFile(EndWorldName + "/world.ini"); + + MoveToWorld(EndWorldName, cRoot::Get()->CreateAndInitializeWorld(EndWorldName)); + break; + } + default: break; + } + } + default: break; + } + } +} + + + + + +bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World) +{ + cWorld * World; + if (a_World == NULL) + { + World = cRoot::Get()->GetWorld(a_WorldName); + if (World == NULL) + { + LOG("%s: Couldn't find world \"%s\".", __FUNCTION__, a_WorldName); + return false; + } + } + else + { + World = a_World; + } + + if (GetWorld() == World) + { + return false; + } + + // Remove all links to the old world + GetWorld()->RemoveEntity(this); + GetWorld()->BroadcastDestroyEntity(*this); + + // Add to all the necessary parts of the new world + SetWorld(World); + World->AddEntity(this); + + return true; +} + + + + + void cEntity::SetSwimState(cChunk & a_Chunk) { int RelY = (int)floor(GetPosY() + 0.1); diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 0c393c0f5..da8256606 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -323,6 +323,9 @@ public: /** Detects the time for application of cacti damage */ virtual void DetectCacti(void); + + /** Detects whether we are in a portal block and begins teleportation procedures if so */ + virtual void DetectPortal(void); /// Handles when the entity is in the void virtual void TickInVoid(cChunk & a_Chunk); @@ -365,6 +368,9 @@ public: /// Teleports to the coordinates specified virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ); + + /** Moves entity to specified world */ + virtual bool MoveToWorld(const AString & a_WorldName, cWorld * a_World = NULL); // tolua_end diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 0dfdcfd8b..140b98d5d 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -134,7 +134,7 @@ cPlayer::~cPlayer(void) SaveToDisk(); - m_World->RemovePlayer( this ); + m_World->RemovePlayer(this); m_ClientHandle = NULL; @@ -150,8 +150,6 @@ cPlayer::~cPlayer(void) void cPlayer::Destroyed() { CloseWindow(false); - - m_ClientHandle = NULL; } @@ -952,7 +950,7 @@ void cPlayer::Respawn(void) m_LifetimeTotalXp = 0; // ToDo: send score to client? How? - m_ClientHandle->SendRespawn(); + m_ClientHandle->SendRespawn(*GetWorld()); // Extinguish the fire: StopBurning(); @@ -1574,12 +1572,25 @@ void cPlayer::TossItems(const cItems & a_Items) -bool cPlayer::MoveToWorld(const char * a_WorldName) +bool cPlayer::MoveToWorld(const AString & a_WorldName, cWorld * a_World) { - cWorld * World = cRoot::Get()->GetWorld(a_WorldName); - if (World == NULL) + cWorld * World; + if (a_World == NULL) + { + World = cRoot::Get()->GetWorld(a_WorldName); + if (World == NULL) + { + LOG("%s: Couldn't find world \"%s\".", __FUNCTION__, a_WorldName); + return false; + } + } + else + { + World = a_World; + } + + if (GetWorld() == World) { - LOG("%s: Couldn't find world \"%s\".", __FUNCTION__, a_WorldName); return false; } @@ -1588,11 +1599,11 @@ bool cPlayer::MoveToWorld(const char * a_WorldName) // Remove all links to the old world m_World->RemovePlayer(this); m_ClientHandle->RemoveFromAllChunks(); - m_World->RemoveEntity(this); // If the dimension is different, we can send the respawn packet // http://wiki.vg/Protocol#0x09 says "don't send if dimension is the same" as of 2013_07_02 - m_ClientHandle->MoveToWorld(*World, (OldDimension != World->GetDimension())); + bool SendRespawn = OldDimension != World->GetDimension(); + m_ClientHandle->MoveToWorld(*World, SendRespawn); // Add player to all the necessary parts of the new world SetWorld(World); @@ -1600,6 +1611,11 @@ bool cPlayer::MoveToWorld(const char * a_WorldName) World->AddEntity(this); World->AddPlayer(this); + if (SendRespawn) + { + GetClientHandle()->SendPlayerMoveLook(); + } + return true; } diff --git a/src/Entities/Player.h b/src/Entities/Player.h index b7cb27d6c..582f79b86 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -328,7 +328,7 @@ public: void SetVisible( bool a_bVisible ); // tolua_export bool IsVisible(void) const { return m_bVisible; } // tolua_export - bool MoveToWorld(const char * a_WorldName); // tolua_export + virtual bool MoveToWorld(const AString & a_WorldName, cWorld * a_World = NULL) override; // tolua_export bool SaveToDisk(void); bool LoadFromDisk(void); diff --git a/src/Generating/BioGen.cpp b/src/Generating/BioGen.cpp index 32a687201..e08e242e2 100644 --- a/src/Generating/BioGen.cpp +++ b/src/Generating/BioGen.cpp @@ -95,7 +95,7 @@ void cBioGenConstant::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap void cBioGenConstant::InitializeBiomeGen(cIniFile & a_IniFile) { - AString Biome = a_IniFile.GetValueSet("Generator", "ConstantBiome", "Plains"); + AString Biome = a_IniFile.GetValueSet("Generator", "ConstantBiome", ""); m_Biome = StringToBiome(Biome); if (m_Biome == biInvalidBiome) { diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index 2e886336f..03ed0291f 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -39,7 +39,6 @@ cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile & { LOGWARN("[Generator] CompositionGen value not set in world.ini, using \"Biomal\"."); CompoGenName = "Biomal"; - a_IniFile.SetValue("Generator", "CompositionGen", CompoGenName); } cTerrainCompositionGen * res = NULL; @@ -93,7 +92,6 @@ cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile & else { LOGWARN("Unknown CompositionGen \"%s\", using \"Biomal\" instead.", CompoGenName.c_str()); - a_IniFile.DeleteValue("Generator", "CompositionGen"); a_IniFile.SetValue("Generator", "CompositionGen", "Biomal"); return CreateCompositionGen(a_IniFile, a_BiomeGen, a_HeightGen, a_Seed); } @@ -291,19 +289,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) int Seed = m_ChunkGenerator.GetSeed(); eDimension Dimension = StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld")); - // Older configuration used "Structures" in addition to "Finishers"; we don't distinguish between the two anymore (#398) - // Therefore, we load Structures from the ini file for compatibility, but move its contents over to Finishers: - AString Structures = a_IniFile.GetValue("Generator", "Structures", ""); - AString Finishers = a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, LavaLakes, OreNests, Trees, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator"); - if (!Structures.empty()) - { - LOGINFO("[Generator].Structures is deprecated, moving the contents to [Generator].Finishers."); - // Structures used to generate before Finishers, so place them first: - Structures.append(", "); - Finishers = Structures + Finishers; - a_IniFile.SetValue("Generator", "Finishers", Finishers); - } - a_IniFile.DeleteValue("Generator", "Structures"); + AString Finishers = a_IniFile.GetValueSet("Generator", "Finishers", ""); // Create all requested finishers: AStringVector Str = StringSplitAndTrim(Finishers, ","); diff --git a/src/Generating/EndGen.cpp b/src/Generating/EndGen.cpp index f466039b9..5be73bfbe 100644 --- a/src/Generating/EndGen.cpp +++ b/src/Generating/EndGen.cpp @@ -50,7 +50,7 @@ cEndGen::cEndGen(int a_Seed) : -void cEndGen::Initialize(cIniFile & a_IniFile) +void cEndGen::InitializeCompoGen(cIniFile & a_IniFile) { m_IslandSizeX = a_IniFile.GetValueSetI("Generator", "EndGenIslandSizeX", m_IslandSizeX); m_IslandSizeY = a_IniFile.GetValueSetI("Generator", "EndGenIslandSizeY", m_IslandSizeY); diff --git a/src/Generating/EndGen.h b/src/Generating/EndGen.h index 4904a0e3d..322061810 100644 --- a/src/Generating/EndGen.h +++ b/src/Generating/EndGen.h @@ -23,8 +23,6 @@ class cEndGen : public: cEndGen(int a_Seed); - void Initialize(cIniFile & a_IniFile); - protected: /// Seed for the noise @@ -66,4 +64,5 @@ protected: // cTerrainCompositionGen overrides: virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override; + virtual void InitializeCompoGen(cIniFile & a_IniFile) override; } ; diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index a543c6361..c6e569919 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -100,7 +100,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0; virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) = 0; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) = 0; - virtual void SendRespawn (void) = 0; + virtual void SendRespawn (const cWorld & a_World) = 0; virtual void SendExperience (void) = 0; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) = 0; virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) = 0; diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp index f3bdae3ac..873295f62 100644 --- a/src/Protocol/Protocol125.cpp +++ b/src/Protocol/Protocol125.cpp @@ -831,12 +831,12 @@ void cProtocol125::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect -void cProtocol125::SendRespawn(void) +void cProtocol125::SendRespawn(const cWorld & a_World) { cCSLock Lock(m_CSPacket); cPlayer * Player = m_Client->GetPlayer(); WriteByte (PACKET_RESPAWN); - WriteInt ((int)(Player->GetWorld()->GetDimension())); + WriteInt ((int)(a_World.GetDimension())); WriteByte (2); // TODO: Difficulty; 2 = Normal WriteChar ((char)Player->GetGameMode()); WriteShort (256); // Current world height diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index 18a626a2d..3f39c8965 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -72,7 +72,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; - virtual void SendRespawn (void) override; + virtual void SendRespawn (const cWorld & a_World) override; virtual void SendExperience (void) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; diff --git a/src/Protocol/Protocol16x.cpp b/src/Protocol/Protocol16x.cpp index 714bf5e46..9e0f3f852 100644 --- a/src/Protocol/Protocol16x.cpp +++ b/src/Protocol/Protocol16x.cpp @@ -158,10 +158,10 @@ void cProtocol161::SendPlayerMaxSpeed(void) -void cProtocol161::SendRespawn(void) +void cProtocol161::SendRespawn(const cWorld & a_World) { // Besides sending the respawn, we need to also send the player max speed, otherwise the client reverts to super-fast - super::SendRespawn(); + super::SendRespawn(a_World); SendPlayerMaxSpeed(); } diff --git a/src/Protocol/Protocol16x.h b/src/Protocol/Protocol16x.h index 8eedce8d5..e91dc8a1c 100644 --- a/src/Protocol/Protocol16x.h +++ b/src/Protocol/Protocol16x.h @@ -42,7 +42,7 @@ protected: virtual void SendGameMode (eGameMode a_GameMode) override; virtual void SendHealth (void) override; virtual void SendPlayerMaxSpeed(void) override; - virtual void SendRespawn (void) override; + virtual void SendRespawn (const cWorld & a_World) override; virtual void SendWindowOpen (const cWindow & a_Window) override; virtual int ParseEntityAction (void) override; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 7c526d103..96e1cbad9 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -983,11 +983,11 @@ void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect -void cProtocol172::SendRespawn(void) +void cProtocol172::SendRespawn(const cWorld & a_World) { cPacketizer Pkt(*this, 0x07); // Respawn packet cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteInt(Player->GetWorld()->GetDimension()); + Pkt.WriteInt((int)a_World.GetDimension()); Pkt.WriteByte(2); // TODO: Difficulty (set to Normal) Pkt.WriteByte((Byte)Player->GetEffectiveGameMode()); Pkt.WriteString("default"); diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index 3c6a8c085..cafdb50e4 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -104,7 +104,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; - virtual void SendRespawn (void) override; + virtual void SendRespawn (const cWorld & a_World) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 virtual void SendExperience (void) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index b0cbb6def..35a331f43 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -555,10 +555,10 @@ void cProtocolRecognizer::SendRemoveEntityEffect(const cEntity & a_Entity, int a -void cProtocolRecognizer::SendRespawn(void) +void cProtocolRecognizer::SendRespawn(const cWorld & a_World) { ASSERT(m_Protocol != NULL); - m_Protocol->SendRespawn(); + m_Protocol->SendRespawn(a_World); } diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index 3a291bf7a..5e178447c 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -107,7 +107,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; - virtual void SendRespawn (void) override; + virtual void SendRespawn (const cWorld & a_World) override; virtual void SendExperience (void) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; diff --git a/src/Root.cpp b/src/Root.cpp index c82b05a66..2a80baeb3 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -320,7 +320,7 @@ cWorld * cRoot::CreateAndInitializeWorld(const AString & a_WorldName) { return NULL; } - cWorld* NewWorld = new cWorld(a_WorldName.c_str()); + cWorld * NewWorld = new cWorld(a_WorldName.c_str()); m_WorldsByName[a_WorldName] = NewWorld; NewWorld->Start(); NewWorld->InitializeSpawn(); @@ -372,7 +372,7 @@ void cRoot::UnloadWorlds(void) -cWorld* cRoot::GetDefaultWorld() +cWorld * cRoot::GetDefaultWorld() { return m_pDefaultWorld; } @@ -381,12 +381,14 @@ cWorld* cRoot::GetDefaultWorld() -cWorld* cRoot::GetWorld( const AString & a_WorldName ) +cWorld * cRoot::GetWorld(const AString & a_WorldName) { - WorldMap::iterator itr = m_WorldsByName.find( a_WorldName ); - if( itr != m_WorldsByName.end() ) + WorldMap::iterator itr = m_WorldsByName.find(a_WorldName); + if (itr != m_WorldsByName.end()) + { return itr->second; - return 0; + } + return NULL; } @@ -398,9 +400,12 @@ bool cRoot::ForEachWorld(cWorldListCallback & a_Callback) for (WorldMap::iterator itr = m_WorldsByName.begin(), itr2 = itr; itr != m_WorldsByName.end(); itr = itr2) { ++itr2; - if (a_Callback.Item(itr->second)) + if (itr->second != NULL) { - return false; + if (a_Callback.Item(itr->second)) + { + return false; + } } } return true; diff --git a/src/World.cpp b/src/World.cpp index 807065bfa..9869e90fa 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -571,6 +571,37 @@ void cWorld::Start(void) m_GameMode = (eGameMode) Clamp(GameMode, (int)gmSurvival, (int)gmAdventure); m_TNTShrapnelLevel = (eShrapnelLevel)Clamp(TNTShrapnelLevel, (int)slNone, (int)slAll); + switch (GetDimension()) + { + case dimEnd: + { + IniFile.GetValueSet("Generator", "BiomeGen", "Constant"); + IniFile.GetValueSet("Generator", "ConstantBiome", "End"); + IniFile.GetValueSet("Generator", "HeightGen", "Biomal"); + IniFile.GetValueSet("Generator", "CompositionGen", "End"); + break; + } + case dimOverworld: + { + IniFile.GetValueSet("Generator", "BiomeGen", "MultiStepMap"); + IniFile.GetValueSet("Generator", "HeightGen", "DistortedHeightmap"); + IniFile.GetValueSet("Generator", "CompositionGen", "DistortedHeightmap"); + IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator"); + break; + } + case dimNether: + { + IniFile.GetValueSet("Generator", "BiomeGen", "Constant"); + IniFile.GetValueSet("Generator", "ConstantBiome", "Nether"); + IniFile.GetValueSet("Generator", "HeightGen", "Flat"); + IniFile.GetValueSet("Generator", "FlatHeight", "128"); + IniFile.GetValueSet("Generator", "CompositionGen", "Nether"); + IniFile.GetValueSet("Generator", "Finishers", "WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherForts, PreSimulator"); + IniFile.GetValueSet("Generator", "BottomLavaHeight", "30"); + break; + } + } + // Load allowed mobs: const char * DefaultMonsters = ""; switch (m_Dimension) -- cgit v1.2.3 From 576f89c1d5bdb067c0ca06237440f754d80bd13c Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 1 Jun 2014 18:46:59 +0100 Subject: Implemented bed homes + Implemented bed home positions * Fixed some inventory and health server/client mismatches after world change --- src/Blocks/BlockBed.cpp | 2 ++ src/Entities/Entity.cpp | 6 ++++++ src/Entities/Player.cpp | 35 ++++++++++++++++++++++------------- src/Entities/Player.h | 15 ++++++++++++--- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp index 07ef997dd..5525f0d0c 100644 --- a/src/Blocks/BlockBed.cpp +++ b/src/Blocks/BlockBed.cpp @@ -133,6 +133,8 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta | 0x4); // Where 0x4 = occupied bit a_Player->SetIsInBed(true); + a_Player->SetBedPos(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); + a_Player->SendMessageSuccess("Home position set successfully"); cTimeFastForwardTester Tester; if (a_WorldInterface.ForEachPlayer(Tester)) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index b5c272cf2..de6c628e9 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1093,6 +1093,12 @@ void cEntity::DetectPortal() File.WriteFile(OverworldName + "/world.ini"); MoveToWorld(OverworldName, cRoot::Get()->CreateAndInitializeWorld(OverworldName)); + + if (IsPlayer()) + { + cPlayer * Player = (cPlayer *)this; + Player->TeleportToCoords(Player->GetLastBedPos().x, Player->GetLastBedPos().y, Player->GetLastBedPos().z); + } break; } case dimOverworld: diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 140b98d5d..3058d6e94 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -82,13 +82,13 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) m_PlayerName = a_PlayerName; - if (!LoadFromDisk()) + cWorld * World; + if (!LoadFromDisk(World)) { m_Inventory.Clear(); - cWorld * DefaultWorld = cRoot::Get()->GetDefaultWorld(); - SetPosX(DefaultWorld->GetSpawnX()); - SetPosY(DefaultWorld->GetSpawnY()); - SetPosZ(DefaultWorld->GetSpawnZ()); + SetPosX(World->GetSpawnX()); + SetPosY(World->GetSpawnY()); + SetPosZ(World->GetSpawnZ()); LOGD("Player \"%s\" is connecting for the first time, spawning at default world spawn {%.2f, %.2f, %.2f}", a_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ() @@ -101,11 +101,6 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) if (m_GameMode == gmNotSet) { - cWorld * World = cRoot::Get()->GetWorld(GetLoadedWorldName()); - if (World == NULL) - { - World = cRoot::Get()->GetDefaultWorld(); - } if (World->IsGameModeCreative()) { m_CanFly = true; @@ -955,7 +950,7 @@ void cPlayer::Respawn(void) // Extinguish the fire: StopBurning(); - TeleportToCoords(GetWorld()->GetSpawnX(), GetWorld()->GetSpawnY(), GetWorld()->GetSpawnZ()); + TeleportToCoords(GetLastBedPos().x, GetLastBedPos().y, GetLastBedPos().z); SetVisible(true); } @@ -1614,6 +1609,8 @@ bool cPlayer::MoveToWorld(const AString & a_WorldName, cWorld * a_World) if (SendRespawn) { GetClientHandle()->SendPlayerMoveLook(); + GetClientHandle()->SendHealth(); + GetClientHandle()->SendWholeInventory((cWindow &)GetInventory()); } return true; @@ -1662,8 +1659,14 @@ void cPlayer::LoadPermissionsFromDisk() -bool cPlayer::LoadFromDisk() +bool cPlayer::LoadFromDisk(cWorld * a_World) { + a_World = cRoot::Get()->GetWorld(GetLoadedWorldName()); + if (a_World == NULL) + { + a_World = cRoot::Get()->GetDefaultWorld(); + } + LoadPermissionsFromDisk(); // Log player permissions, cause it's what the cool kids do @@ -1724,6 +1727,9 @@ bool cPlayer::LoadFromDisk() m_LifetimeTotalXp = (short) root.get("xpTotal", 0).asInt(); m_CurrentXp = (short) root.get("xpCurrent", 0).asInt(); m_IsFlying = root.get("isflying", 0).asBool(); + m_LastBedPos.x = root.get("SpawnX", a_World->GetSpawnX()).asInt(); + m_LastBedPos.y = root.get("SpawnY", a_World->GetSpawnY()).asInt(); + m_LastBedPos.z = root.get("SpawnZ", a_World->GetSpawnZ()).asInt(); m_GameMode = (eGameMode) root.get("gamemode", eGameMode_NotSet).asInt(); @@ -1742,7 +1748,7 @@ bool cPlayer::LoadFromDisk() StatSerializer.Load(); LOGD("Player \"%s\" was read from file, spawning at {%.2f, %.2f, %.2f} in world \"%s\"", - GetName().c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str() + GetName().c_str(), GetPosX(), GetPosY(), GetPosZ(), GetLoadedWorldName().c_str() ); return true; @@ -1784,6 +1790,9 @@ bool cPlayer::SaveToDisk() root["foodExhaustion"] = m_FoodExhaustionLevel; root["world"] = GetWorld()->GetName(); root["isflying"] = IsFlying(); + root["SpawnX"] = GetLastBedPos().x; + root["SpawnY"] = GetLastBedPos().y; + root["SpawnZ"] = GetLastBedPos().z; if (m_GameMode == GetWorld()->GetGameMode()) { diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 582f79b86..5c0b61064 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -331,7 +331,7 @@ public: virtual bool MoveToWorld(const AString & a_WorldName, cWorld * a_World = NULL) override; // tolua_export bool SaveToDisk(void); - bool LoadFromDisk(void); + bool LoadFromDisk(cWorld * a_World); void LoadPermissionsFromDisk(void); // tolua_export const AString & GetLoadedWorldName() { return m_LoadedWorldName; } @@ -391,11 +391,19 @@ public: /** If true the player can fly even when he's not in creative. */ void SetCanFly(bool a_CanFly); + /** Gets the last position that the player slept in */ + Vector3i GetLastBedPos(void) const { return m_LastBedPos; } + + /** Sets the player's bed (home) position */ + void SetBedPos(const Vector3i & a_Pos) { m_LastBedPos = a_Pos; } + /** Update movement-related statistics. */ void UpdateMovementStats(const Vector3d & a_DeltaPos); /** Returns wheter the player can fly or not. */ virtual bool CanFly(void) const { return m_CanFly; } + + // tolua_end // cEntity overrides: @@ -450,6 +458,9 @@ protected: cWindow * m_CurrentWindow; cWindow * m_InventoryWindow; + /** The player's last saved bed position */ + Vector3i m_LastBedPos; + char m_Color; eGameMode m_GameMode; @@ -508,8 +519,6 @@ protected: cStatManager m_Stats; - - void ResolvePermissions(void); void ResolveGroups(void); -- cgit v1.2.3 From 01f38d883602045e84fdf98bf3395e97608d9aad Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 4 Jun 2014 13:22:50 +0100 Subject: Added checks for no downfall biomes --- src/Blocks/BlockCauldron.h | 2 +- src/Entities/Entity.cpp | 2 +- src/Mobs/Monster.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Blocks/BlockCauldron.h b/src/Blocks/BlockCauldron.h index 8b5cd9ccb..5ec776df6 100644 --- a/src/Blocks/BlockCauldron.h +++ b/src/Blocks/BlockCauldron.h @@ -61,7 +61,7 @@ public: virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { - if (!a_WorldInterface.IsWeatherWet()) + if (IsBiomeNoDownfall(a_Chunk.GetBiomeAt(a_RelX, a_RelZ)) || !a_WorldInterface.IsWeatherWet()) { return; } diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index de6c628e9..16264a608 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -869,7 +869,7 @@ void cEntity::TickBurning(cChunk & a_Chunk) // Remember the current burning state: bool HasBeenBurning = (m_TicksLeftBurning > 0); - if (m_World->IsWeatherWet()) + if (IsBiomeNoDownfall(a_Chunk.GetBiomeAt(POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width, POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width)) || GetWorld()->IsWeatherWet()) { if (POSY_TOINT > m_World->GetHeight(POSX_TOINT, POSZ_TOINT)) { diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index fa3969d5e..c25ee6b75 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -1034,7 +1034,7 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk) (a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand (GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime !IsOnFire() && // Not already burning - (GetWorld()->IsWeatherWet()) // Not raining + (IsBiomeNoDownfall(a_Chunk.GetBiomeAt(RelX, RelZ)) || GetWorld()->IsWeatherWet()) // Not raining ) { // Burn for 100 ticks, then decide again -- cgit v1.2.3 From 3278a403b5bc951818ed418c39c64934d55dbd65 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 4 Jun 2014 13:24:43 +0100 Subject: Removed use of auto --- src/Chunk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 59f4a8507..c6122852a 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -588,7 +588,7 @@ void cChunk::Tick(float a_Dt) for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) { - auto itr2 = std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), (*itr)->GetUniqueID()); + std::vector::const_iterator itr2 = std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), (*itr)->GetUniqueID()); if (itr2 != m_EntitiesToRemove.end()) { itr = m_Entities.erase(itr); -- cgit v1.2.3 From 74cd4f552152f73d0d46cf726bcef472841e2da5 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 4 Jun 2014 18:59:56 +0100 Subject: Suggestions --- src/Entities/Player.cpp | 2 +- src/Entities/Player.h | 12 ++++++++---- src/UI/Window.cpp | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 02a55566c..8e4c89f68 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1659,7 +1659,7 @@ void cPlayer::LoadPermissionsFromDisk() -bool cPlayer::LoadFromDisk(cWorld * a_World) +bool cPlayer::LoadFromDisk(cWorld *& a_World) { a_World = cRoot::Get()->GetWorld(GetLoadedWorldName()); if (a_World == NULL) diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 5c0b61064..39031fbfb 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -127,7 +127,7 @@ public: inline const cItem & GetEquippedItem(void) const { return GetInventory().GetEquippedItem(); } // tolua_export - /** Returns whether the player is climbing (ladders, vines e.t.c). */ + /** Returns whether the player is climbing (ladders, vines etc.) */ bool IsClimbing(void) const; virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) override; @@ -330,8 +330,13 @@ public: virtual bool MoveToWorld(const AString & a_WorldName, cWorld * a_World = NULL) override; // tolua_export + /** Saves all player data, such as inventory, to JSON */ bool SaveToDisk(void); - bool LoadFromDisk(cWorld * a_World); + + /** Loads player data from JSON to the object + Takes a (NULL) cWorld pointer which it will assign a value to based on either the loaded world or default world + */ + bool LoadFromDisk(cWorld *& a_World); void LoadPermissionsFromDisk(void); // tolua_export const AString & GetLoadedWorldName() { return m_LoadedWorldName; } @@ -342,8 +347,7 @@ public: void SendExperience(void); - // In UI windows, the item that the player is dragging: - bool IsDraggingItem(void) const { return !m_DraggingItem.IsEmpty(); } + /** In UI windows, the item that the player is dragging */ cItem & GetDraggingItem(void) {return m_DraggingItem; } // In UI windows, when inventory-painting: diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp index 46885390b..c0e2cef64 100644 --- a/src/UI/Window.cpp +++ b/src/UI/Window.cpp @@ -283,7 +283,7 @@ void cWindow::OpenedByPlayer(cPlayer & a_Player) bool cWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) { // Checks whether the player is still holding an item - if (a_Player.IsDraggingItem()) + if (!a_Player.GetDraggingItem().IsEmpty()) { LOGD("Player holds item! Dropping it..."); a_Player.TossHeldItem(a_Player.GetDraggingItem().m_ItemCount); -- cgit v1.2.3 From ccbf6cc446ad67fbba8163d4d4d61456c1ba0bc6 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 4 Jun 2014 20:00:55 +0100 Subject: Configurable portals --- src/Entities/Entity.cpp | 45 ++++++++++++++++++++++++++++++++------------- src/Entities/Player.cpp | 2 +- src/World.cpp | 26 ++++++++++++++++++++++++++ src/World.h | 24 ++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 14 deletions(-) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 16264a608..7d9c10ec6 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1042,6 +1042,11 @@ void cEntity::DetectCacti(void) void cEntity::DetectPortal() { + if (!GetWorld()->AreNetherPortalsEnabled() && !GetWorld()->AreEndPortalsEnabled()) + { + return; + } + int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT; if ((Y > 0) && (Y < cChunkDef::Height)) { @@ -1049,11 +1054,18 @@ void cEntity::DetectPortal() { case E_BLOCK_NETHER_PORTAL: { + if (!GetWorld()->AreNetherPortalsEnabled()) + { + return; + } + switch (GetWorld()->GetDimension()) { case dimNether: { - AString OverworldName = GetWorld()->GetName().substr(0, GetWorld()->GetName().size() - 7); + cIniFile OwnIni; OwnIni.ReadFile(GetWorld()->GetIniFileName()); + AString OverworldName = OwnIni.GetValue("General", "OverworldName", cRoot::Get()->GetDefaultWorld()->GetName()); + cFile::CreateFolder(FILE_IO_PREFIX + OverworldName); cIniFile File; File.ReadFile(OverworldName + "/world.ini"); @@ -1065,14 +1077,14 @@ void cEntity::DetectPortal() } case dimOverworld: { - AString NetherWorldName = GetWorld()->GetName() + "_nether"; - cFile::CreateFolder(FILE_IO_PREFIX + NetherWorldName); + cFile::CreateFolder(FILE_IO_PREFIX + GetWorld()->GetNetherWorldName()); cIniFile File; - File.ReadFile(NetherWorldName + "/world.ini"); + File.ReadFile(GetWorld()->GetNetherWorldName() + "/world.ini"); File.SetValue("General", "Dimension", "Nether"); - File.WriteFile(NetherWorldName + "/world.ini"); + File.SetValue("General", "OverworldName", GetWorld()->GetName()); + File.WriteFile(GetWorld()->GetNetherWorldName() + "/world.ini"); - MoveToWorld(NetherWorldName, cRoot::Get()->CreateAndInitializeWorld(NetherWorldName)); + MoveToWorld(GetWorld()->GetNetherWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName())); break; } default: break; @@ -1081,11 +1093,18 @@ void cEntity::DetectPortal() } case E_BLOCK_END_PORTAL: { + if (!GetWorld()->AreEndPortalsEnabled()) + { + return; + } + switch (GetWorld()->GetDimension()) { case dimEnd: { - AString OverworldName = GetWorld()->GetName().substr(0, GetWorld()->GetName().size() - 4); + cIniFile OwnIni; OwnIni.ReadFile(GetWorld()->GetIniFileName()); + AString OverworldName = OwnIni.GetValue("General", "OverworldName", cRoot::Get()->GetDefaultWorld()->GetName()); + cFile::CreateFolder(FILE_IO_PREFIX + OverworldName); cIniFile File; File.ReadFile(OverworldName + "/world.ini"); @@ -1103,14 +1122,14 @@ void cEntity::DetectPortal() } case dimOverworld: { - AString EndWorldName = GetWorld()->GetName() + "_end"; - cFile::CreateFolder(FILE_IO_PREFIX + EndWorldName); + cFile::CreateFolder(FILE_IO_PREFIX + GetWorld()->GetEndWorldName()); cIniFile File; - File.ReadFile(EndWorldName + "/world.ini"); + File.ReadFile(GetWorld()->GetEndWorldName() + "/world.ini"); File.SetValue("General", "Dimension", "End"); - File.WriteFile(EndWorldName + "/world.ini"); + File.SetValue("General", "OverworldName", GetWorld()->GetName()); + File.WriteFile(GetWorld()->GetEndWorldName() + "/world.ini"); - MoveToWorld(EndWorldName, cRoot::Get()->CreateAndInitializeWorld(EndWorldName)); + MoveToWorld(GetWorld()->GetEndWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName())); break; } default: break; @@ -1133,7 +1152,7 @@ bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World) World = cRoot::Get()->GetWorld(a_WorldName); if (World == NULL) { - LOG("%s: Couldn't find world \"%s\".", __FUNCTION__, a_WorldName); + LOG("%s: Couldn't find world \"%s\".", __FUNCTION__, a_WorldName.c_str()); return false; } } diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 8e4c89f68..eebc9ecf9 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1610,7 +1610,7 @@ bool cPlayer::MoveToWorld(const AString & a_WorldName, cWorld * a_World) { GetClientHandle()->SendPlayerMoveLook(); GetClientHandle()->SendHealth(); - GetClientHandle()->SendWholeInventory((cWindow &)GetInventory()); + GetClientHandle()->SendWholeInventory(*GetWindow()); } return true; diff --git a/src/World.cpp b/src/World.cpp index 66aca83ef..345c894eb 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -66,6 +66,9 @@ const int TIME_NIGHT_END = 22812; const int TIME_SUNRISE = 23999; const int TIME_SPAWN_DIVISOR = 148; +#define DEFAULT_NETHER_NAME GetName() + "_nether" +#define DEFAULT_END_NAME GetName() + "_end" + @@ -566,6 +569,14 @@ void cWorld::Start(void) m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true); m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true); int GameMode = IniFile.GetValueSetI("General", "Gamemode", (int)m_GameMode); + + if ((GetDimension() != dimNether) && (GetDimension() != dimEnd)) + { + m_bNetherPortalsEnabled = IniFile.GetValueSetB("General", "NetherPortalsEnabled", true); + m_NetherWorldName = IniFile.GetValueSet("General", "NetherWorldName", DEFAULT_NETHER_NAME); + m_bEndPortalsEnabled = IniFile.GetValueSetB("General", "EndPortalsEnabled", true); + m_EndWorldName = IniFile.GetValueSet("General", "EndWorldName", DEFAULT_END_NAME); + } // Adjust the enum-backed variables into their respective bounds: m_GameMode = (eGameMode) Clamp(GameMode, (int)gmSurvival, (int)gmAdventure); @@ -734,6 +745,21 @@ void cWorld::Stop(void) } // for itr - m_Clients[] m_Clients.clear(); } + + // Write settings to file; these are all plugin changeable values - keep updated! + cIniFile IniFile; + IniFile.ReadFile(m_IniFileName); + if ((GetDimension() != dimNether) && (GetDimension() != dimEnd)) + { + IniFile.SetValueB("General", "NetherPortalsEnabled", m_bNetherPortalsEnabled); + IniFile.SetValue("General", "NetherWorldName", m_NetherWorldName); + IniFile.SetValueB("General", "EndPortalsEnabled", m_bEndPortalsEnabled); + IniFile.SetValue("General", "EndWorldName", m_EndWorldName); + } + IniFile.SetValueI("Physics", "TNTShrapnelLevel", (int)m_TNTShrapnelLevel); + IniFile.SetValueB("Mechanics", "CommandBlocksEnabled", m_bCommandBlocksEnabled); + IniFile.SetValueB("Mechanics", "UseChatPrefixes", m_bUseChatPrefixes); + IniFile.WriteFile(m_IniFileName); m_TickThread.Stop(); m_Lighting.Stop(); diff --git a/src/World.h b/src/World.h index e72675194..7b87a76ac 100644 --- a/src/World.h +++ b/src/World.h @@ -624,6 +624,18 @@ public: bool ShouldUseChatPrefixes(void) const { return m_bUseChatPrefixes; } void SetShouldUseChatPrefixes(bool a_Flag) { m_bUseChatPrefixes = a_Flag; } + + bool AreNetherPortalsEnabled(void) const { return m_bNetherPortalsEnabled; } + void SetNetherPortalsEnabled(bool a_Flag) { m_bNetherPortalsEnabled = a_Flag; } + + bool AreEndPortalsEnabled(void) const { return m_bEndPortalsEnabled; } + void SetEndPortalsEnabled(bool a_Flag) { m_bEndPortalsEnabled = a_Flag; } + + AString GetNetherWorldName(void) const { return m_NetherWorldName; } + void SetNetherWorldName(const AString & a_Name) { m_NetherWorldName = a_Name; } + + AString GetEndWorldName(void) const { return m_EndWorldName; } + void SetEndWorldName(const AString & a_Name) { m_EndWorldName = a_Name; } // tolua_end @@ -886,6 +898,18 @@ private: See the eShrapnelLevel enumeration for details */ eShrapnelLevel m_TNTShrapnelLevel; + + /** Whether nether portals teleport entities */ + bool m_bNetherPortalsEnabled; + + /** Whether end portals teleport entities */ + bool m_bEndPortalsEnabled; + + /** Name of the nether world */ + AString m_NetherWorldName; + + /** Name of the end world */ + AString m_EndWorldName; cChunkGenerator m_Generator; -- cgit v1.2.3 From 7d3d9e92e89e726fc3e999ac343db06b694d95e7 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 4 Jun 2014 20:01:05 +0100 Subject: Fixed a NetherFinisher bug --- src/Generating/ChunkDesc.cpp | 21 --------------------- src/Generating/ChunkDesc.h | 3 --- src/Generating/FinishGen.cpp | 9 +++++++++ 3 files changed, 9 insertions(+), 24 deletions(-) diff --git a/src/Generating/ChunkDesc.cpp b/src/Generating/ChunkDesc.cpp index 7711723fc..759d57b83 100644 --- a/src/Generating/ChunkDesc.cpp +++ b/src/Generating/ChunkDesc.cpp @@ -20,7 +20,6 @@ cChunkDesc::cChunkDesc(int a_ChunkX, int a_ChunkZ) : m_bUseDefaultBiomes(true), m_bUseDefaultHeight(true), m_bUseDefaultComposition(true), - m_bUseDefaultStructures(true), m_bUseDefaultFinish(true) { m_BlockArea.Create(cChunkDef::Width, cChunkDef::Height, cChunkDef::Width); @@ -207,26 +206,6 @@ bool cChunkDesc::IsUsingDefaultComposition(void) const -void cChunkDesc::SetUseDefaultStructures(bool a_bUseDefaultStructures) -{ - LOGWARNING("%s: Structures are no longer accounted for, use Finishers instead", __FUNCTION__); - m_bUseDefaultStructures = a_bUseDefaultStructures; -} - - - - - -bool cChunkDesc::IsUsingDefaultStructures(void) const -{ - LOGWARNING("%s: Structures are no longer accounted for, use Finishers instead", __FUNCTION__); - return m_bUseDefaultStructures; -} - - - - - void cChunkDesc::SetUseDefaultFinish(bool a_bUseDefaultFinish) { m_bUseDefaultFinish = a_bUseDefaultFinish; diff --git a/src/Generating/ChunkDesc.h b/src/Generating/ChunkDesc.h index 8edc2800b..2680fe3fa 100644 --- a/src/Generating/ChunkDesc.h +++ b/src/Generating/ChunkDesc.h @@ -68,8 +68,6 @@ public: bool IsUsingDefaultHeight(void) const; void SetUseDefaultComposition(bool a_bUseDefaultComposition); bool IsUsingDefaultComposition(void) const; - void SetUseDefaultStructures(bool a_bUseDefaultStructures); - bool IsUsingDefaultStructures(void) const; void SetUseDefaultFinish(bool a_bUseDefaultFinish); bool IsUsingDefaultFinish(void) const; @@ -214,7 +212,6 @@ private: bool m_bUseDefaultBiomes; bool m_bUseDefaultHeight; bool m_bUseDefaultComposition; - bool m_bUseDefaultStructures; bool m_bUseDefaultFinish; } ; // tolua_export diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index f2d66af70..c77145bc6 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -125,6 +125,15 @@ void cFinishGenNetherClumpFoliage::TryPlaceClump(cChunkDesc & a_ChunkDesc, int a float zz = (float) a_ChunkDesc.GetChunkZ() * cChunkDef::Width + z; for (int y = a_RelY - 2; y < a_RelY + 2; y++) { + if ( + ((x < 0) || (x >= cChunkDef::Width)) || + ((y < 0) || (y >= cChunkDef::Height)) || + ((z < 0) || (z >= cChunkDef::Width)) + ) + { + continue; + } + if (a_ChunkDesc.GetBlockType(x, y, z) != E_BLOCK_AIR) // Don't replace non air blocks. { continue; -- cgit v1.2.3 From 9c7a6bc443605612c09be824c452b9287fa2bfdb Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 4 Jun 2014 20:09:02 +0100 Subject: Health of monsters is now saved --- src/WorldStorage/NBTChunkSerializer.cpp | 1 + src/WorldStorage/WSSAnvil.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index a3b0d57be..70c07af50 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -484,6 +484,7 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster) m_Writer.AddFloat("", a_Monster->GetDropChanceBoots()); m_Writer.EndList(); m_Writer.AddByte("CanPickUpLoot", (char)a_Monster->CanPickUpLoot()); + m_Writer.AddShort("Health", (short)a_Monster->GetHealth()); switch (a_Monster->GetMobType()) { case cMonster::mtBat: diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 1891762fd..f58e876e0 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -2456,6 +2456,7 @@ bool cWSSAnvil::LoadMonsterBaseFromNBT(cMonster & a_Monster, const cParsedNBT & a_Monster.SetDropChanceBoots(DropChance[4]); bool CanPickUpLoot = (a_NBT.GetByte(a_NBT.FindChildByName(a_TagIdx, "CanPickUpLoot")) == 1); a_Monster.SetCanPickUpLoot(CanPickUpLoot); + a_Monster.SetHealth(a_NBT.GetShort(a_NBT.FindChildByName(a_TagIdx, "Health"))); return true; } -- cgit v1.2.3 From ea49abd113050eb36fb85ac792cdab0e901b77e6 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 4 Jun 2014 20:52:54 +0100 Subject: Time and weather is saved, part of #1058 Also fixed unreliability in Health and LootPickup loading. --- src/World.cpp | 12 ++++++++++++ src/WorldStorage/WSSAnvil.cpp | 13 ++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/World.cpp b/src/World.cpp index 345c894eb..739ae39d4 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -11,6 +11,7 @@ #include "ChunkMap.h" #include "Generating/ChunkDesc.h" #include "OSSupport/Timer.h" +#include // Serializers #include "WorldStorage/ScoreboardSerializer.h" @@ -569,6 +570,11 @@ void cWorld::Start(void) m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true); m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true); int GameMode = IniFile.GetValueSetI("General", "Gamemode", (int)m_GameMode); + int Weather = IniFile.GetValueSetI("General", "Weather", (int)m_Weather); + + std::stringstream ss; + ss << m_TimeOfDay; + Int64 TimeOfDay = _atoi64(IniFile.GetValueSet("General", "TimeInTicks", ss.str()).c_str()); if ((GetDimension() != dimNether) && (GetDimension() != dimEnd)) { @@ -581,6 +587,7 @@ void cWorld::Start(void) // Adjust the enum-backed variables into their respective bounds: m_GameMode = (eGameMode) Clamp(GameMode, (int)gmSurvival, (int)gmAdventure); m_TNTShrapnelLevel = (eShrapnelLevel)Clamp(TNTShrapnelLevel, (int)slNone, (int)slAll); + m_Weather = (eWeather) Clamp(Weather, (int)wSunny, (int)wStorm); switch (GetDimension()) { @@ -759,6 +766,11 @@ void cWorld::Stop(void) IniFile.SetValueI("Physics", "TNTShrapnelLevel", (int)m_TNTShrapnelLevel); IniFile.SetValueB("Mechanics", "CommandBlocksEnabled", m_bCommandBlocksEnabled); IniFile.SetValueB("Mechanics", "UseChatPrefixes", m_bUseChatPrefixes); + IniFile.SetValueI("General", "Weather", (int)m_Weather); + + std::stringstream ss; + ss << m_TimeOfDay; + IniFile.SetValue("General", "TimeInTicks", ss.str()); IniFile.WriteFile(m_IniFileName); m_TickThread.Stop(); diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index f58e876e0..c84763ac2 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -2454,9 +2454,16 @@ bool cWSSAnvil::LoadMonsterBaseFromNBT(cMonster & a_Monster, const cParsedNBT & a_Monster.SetDropChanceChestplate(DropChance[2]); a_Monster.SetDropChanceLeggings(DropChance[3]); a_Monster.SetDropChanceBoots(DropChance[4]); - bool CanPickUpLoot = (a_NBT.GetByte(a_NBT.FindChildByName(a_TagIdx, "CanPickUpLoot")) == 1); - a_Monster.SetCanPickUpLoot(CanPickUpLoot); - a_Monster.SetHealth(a_NBT.GetShort(a_NBT.FindChildByName(a_TagIdx, "Health"))); + + int LootTag = a_NBT.FindChildByName(a_TagIdx, "CanPickUpLoot"); + if (LootTag > 0) + { + bool CanPickUpLoot = (a_NBT.GetByte(LootTag) == 1); + a_Monster.SetCanPickUpLoot(CanPickUpLoot); + } + + int HealthTag = a_NBT.FindChildByName(a_TagIdx, "Health"); + a_Monster.SetHealth(HealthTag > 0 ? a_NBT.GetShort(HealthTag) : a_Monster.GetMaxHealth()); return true; } -- cgit v1.2.3 From 873043c8e46dfd1ec764fbd5b673173ffe88271f Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 4 Jun 2014 21:51:19 +0100 Subject: Suggestions --- src/Entities/Entity.cpp | 6 ++++-- src/Entities/Player.cpp | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 7d9c10ec6..2d8f385cb 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1063,7 +1063,8 @@ void cEntity::DetectPortal() { case dimNether: { - cIniFile OwnIni; OwnIni.ReadFile(GetWorld()->GetIniFileName()); + cIniFile OwnIni; + OwnIni.ReadFile(GetWorld()->GetIniFileName()); AString OverworldName = OwnIni.GetValue("General", "OverworldName", cRoot::Get()->GetDefaultWorld()->GetName()); cFile::CreateFolder(FILE_IO_PREFIX + OverworldName); @@ -1102,7 +1103,8 @@ void cEntity::DetectPortal() { case dimEnd: { - cIniFile OwnIni; OwnIni.ReadFile(GetWorld()->GetIniFileName()); + cIniFile OwnIni; + OwnIni.ReadFile(GetWorld()->GetIniFileName()); AString OverworldName = OwnIni.GetValue("General", "OverworldName", cRoot::Get()->GetDefaultWorld()->GetName()); cFile::CreateFolder(FILE_IO_PREFIX + OverworldName); diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index eebc9ecf9..c2f384abf 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -89,6 +89,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) SetPosX(World->GetSpawnX()); SetPosY(World->GetSpawnY()); SetPosZ(World->GetSpawnZ()); + SetBedPos(Vector3i(World->GetSpawnX(), World->GetSpawnY(), World->GetSpawnZ())); LOGD("Player \"%s\" is connecting for the first time, spawning at default world spawn {%.2f, %.2f, %.2f}", a_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ() -- cgit v1.2.3 From f22a1b226ca1f5969ab9882c3f9c6f00c6c90aa2 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Thu, 5 Jun 2014 08:25:26 +0100 Subject: Fixed compilation --- src/Entities/Player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index c2f384abf..af4299e4b 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1576,7 +1576,7 @@ bool cPlayer::MoveToWorld(const AString & a_WorldName, cWorld * a_World) World = cRoot::Get()->GetWorld(a_WorldName); if (World == NULL) { - LOG("%s: Couldn't find world \"%s\".", __FUNCTION__, a_WorldName); + LOG("%s: Couldn't find world \"%s\".", __FUNCTION__, a_WorldName.c_str()); return false; } } -- cgit v1.2.3 From b73bf1a1e37a9455ff32cef37d23e0441d6ec555 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Thu, 5 Jun 2014 08:28:01 +0100 Subject: Fixed decision failure --- src/Mobs/Monster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index c25ee6b75..0f030da2d 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -1034,7 +1034,7 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk) (a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand (GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime !IsOnFire() && // Not already burning - (IsBiomeNoDownfall(a_Chunk.GetBiomeAt(RelX, RelZ)) || GetWorld()->IsWeatherWet()) // Not raining + (IsBiomeNoDownfall(a_Chunk.GetBiomeAt(RelX, RelZ)) || !GetWorld()->IsWeatherWet()) // Not raining ) { // Burn for 100 ticks, then decide again -- cgit v1.2.3 From 156c9851b8a099656fa86ea52d989e35e5b7ebf1 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Thu, 5 Jun 2014 17:58:29 +0100 Subject: Suggestions --- lib/inifile/iniFile.cpp | 20 ++++++++++++++++++++ lib/inifile/iniFile.h | 2 ++ src/Blocks/WorldInterface.h | 4 +++- src/Chunk.cpp | 7 +++++-- src/Generating/ChunkGenerator.cpp | 2 +- src/World.cpp | 11 ++--------- src/World.h | 4 +++- 7 files changed, 36 insertions(+), 14 deletions(-) diff --git a/lib/inifile/iniFile.cpp b/lib/inifile/iniFile.cpp index ea03f5d35..7515483df 100644 --- a/lib/inifile/iniFile.cpp +++ b/lib/inifile/iniFile.cpp @@ -447,6 +447,15 @@ bool cIniFile::SetValueI(const AString & a_KeyName, const AString & a_ValueName, +bool cIniFile::SetValueI(const AString & a_Keyname, const AString & a_ValueName, const Int64 a_Value, const bool a_CreateIfNotExists) +{ + return SetValue(a_Keyname, a_ValueName, Printf("lld", a_Value), a_CreateIfNotExists); +} + + + + + bool cIniFile::SetValueF(const AString & a_KeyName, const AString & a_ValueName, double const a_Value, const bool a_CreateIfNotExists) { return SetValue(a_KeyName, a_ValueName, Printf("%f", a_Value), a_CreateIfNotExists); @@ -571,6 +580,17 @@ int cIniFile::GetValueSetI(const AString & keyname, const AString & valuename, c +Int64 cIniFile::GetValueSetI(const AString & keyname, const AString & valuename, const Int64 defValue) +{ + AString Data; + Printf(Data, "%lld", defValue); + return std::stoll(GetValueSet(keyname, valuename, Data)); +} + + + + + bool cIniFile::DeleteValueByID(const int keyID, const int valueID) { if ((keyID < (int)keys.size()) && (valueID < (int)keys[keyID].names.size())) diff --git a/lib/inifile/iniFile.h b/lib/inifile/iniFile.h index 0bf1d917e..58fecd0cf 100644 --- a/lib/inifile/iniFile.h +++ b/lib/inifile/iniFile.h @@ -119,6 +119,7 @@ public: AString GetValueSet (const AString & keyname, const AString & valuename, const AString & defValue = ""); double GetValueSetF(const AString & keyname, const AString & valuename, const double defValue = 0.0); int GetValueSetI(const AString & keyname, const AString & valuename, const int defValue = 0); + Int64 GetValueSetI(const AString & keyname, const AString & valuename, const Int64 defValue = 0); bool GetValueSetB(const AString & keyname, const AString & valuename, const bool defValue = false) { return (GetValueSetI(keyname, valuename, defValue ? 1 : 0) != 0); @@ -141,6 +142,7 @@ public: bool SetValue (const int keyID, const int valueID, const AString & value); bool SetValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value, const bool a_CreateIfNotExists = true); bool SetValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value, const bool a_CreateIfNotExists = true); + bool SetValueI(const AString & a_Keyname, const AString & a_ValueName, const Int64 a_Value, const bool a_CreateIfNotExists = true); bool SetValueB(const AString & a_KeyName, const AString & a_ValueName, const bool a_Value, const bool a_CreateIfNotExists = true) { return SetValueI(a_KeyName, a_ValueName, int(a_Value), a_CreateIfNotExists); diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h index 08600d502..7df82197e 100644 --- a/src/Blocks/WorldInterface.h +++ b/src/Blocks/WorldInterface.h @@ -37,7 +37,9 @@ public: virtual void SetTimeOfDay(Int64 a_TimeOfDay) = 0; - /** Returns true if the current weather has any precipitation - rain or storm */ + /** Returns true if the current weather has any precipitation - rain or storm + Does not check if biome has no downfall, use cChunk::GetBiomeAt(RelX, RelZ) for that + */ virtual bool IsWeatherWet(void) const = 0; }; diff --git a/src/Chunk.cpp b/src/Chunk.cpp index c6122852a..2850dd93b 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -580,7 +580,10 @@ void cChunk::Tick(float a_Dt) { // Mobs are tickes inside MobTick (as we don't have to tick them if they are far away from players) // Don't tick things queued to be removed - if (!((*itr)->IsMob()) && (std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), (*itr)->GetUniqueID()) == m_EntitiesToRemove.end())) + if ( + !((*itr)->IsMob()) && + (std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), (*itr)->GetUniqueID()) == m_EntitiesToRemove.end()) + ) { (*itr)->Tick(a_Dt, *this); } @@ -588,7 +591,7 @@ void cChunk::Tick(float a_Dt) for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) { - std::vector::const_iterator itr2 = std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), (*itr)->GetUniqueID()); + std::vector::iterator itr2 = std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), (*itr)->GetUniqueID()); if (itr2 != m_EntitiesToRemove.end()) { itr = m_Entities.erase(itr); diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp index 73f0223e8..1f2958901 100644 --- a/src/Generating/ChunkGenerator.cpp +++ b/src/Generating/ChunkGenerator.cpp @@ -52,7 +52,7 @@ bool cChunkGenerator::Start(cPluginInterface & a_PluginInterface, cChunkSink & a m_ChunkSink = &a_ChunkSink; MTRand rnd; - m_Seed = a_IniFile.GetValueSetI("Seed", "Seed", rnd.randInt()); + m_Seed = a_IniFile.GetValueSetI("Seed", "Seed", (int)rnd.randInt()); AString GeneratorName = a_IniFile.GetValueSet("Generator", "Generator", "Composable"); if (NoCaseCompare(GeneratorName, "Noise3D") == 0) diff --git a/src/World.cpp b/src/World.cpp index 739ae39d4..3e02caf8e 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -11,7 +11,6 @@ #include "ChunkMap.h" #include "Generating/ChunkDesc.h" #include "OSSupport/Timer.h" -#include // Serializers #include "WorldStorage/ScoreboardSerializer.h" @@ -571,10 +570,7 @@ void cWorld::Start(void) m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true); int GameMode = IniFile.GetValueSetI("General", "Gamemode", (int)m_GameMode); int Weather = IniFile.GetValueSetI("General", "Weather", (int)m_Weather); - - std::stringstream ss; - ss << m_TimeOfDay; - Int64 TimeOfDay = _atoi64(IniFile.GetValueSet("General", "TimeInTicks", ss.str()).c_str()); + Int64 TimeOfDay = IniFile.GetValueSetI("General", "TimeInTicks", m_TimeOfDay); if ((GetDimension() != dimNether) && (GetDimension() != dimEnd)) { @@ -767,10 +763,7 @@ void cWorld::Stop(void) IniFile.SetValueB("Mechanics", "CommandBlocksEnabled", m_bCommandBlocksEnabled); IniFile.SetValueB("Mechanics", "UseChatPrefixes", m_bUseChatPrefixes); IniFile.SetValueI("General", "Weather", (int)m_Weather); - - std::stringstream ss; - ss << m_TimeOfDay; - IniFile.SetValue("General", "TimeInTicks", ss.str()); + IniFile.SetValueI("General", "TimeInTicks", m_TimeOfDay); IniFile.WriteFile(m_IniFileName); m_TickThread.Stop(); diff --git a/src/World.h b/src/World.h index 7b87a76ac..80f69f22f 100644 --- a/src/World.h +++ b/src/World.h @@ -715,7 +715,9 @@ public: bool IsWeatherRain (void) const { return (m_Weather == wRain); } bool IsWeatherStorm(void) const { return (m_Weather == wStorm); } - /** Returns true if the current weather has any precipitation - rain or storm */ + /** Returns true if the current weather has any precipitation - rain or storm + Does not check if biome has no downfall, use cChunk::GetBiomeAt(RelX, RelZ) for that + */ virtual bool IsWeatherWet(void) const override { return (m_Weather != wSunny); } // tolua_end -- cgit v1.2.3 From 43342540c80169c1d539751cfd48cae99d97e058 Mon Sep 17 00:00:00 2001 From: worktycho Date: Fri, 6 Jun 2014 23:54:24 +0100 Subject: Fixed Time of day --- src/World.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/World.cpp b/src/World.cpp index 3e02caf8e..1b5582b81 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -570,7 +570,7 @@ void cWorld::Start(void) m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true); int GameMode = IniFile.GetValueSetI("General", "Gamemode", (int)m_GameMode); int Weather = IniFile.GetValueSetI("General", "Weather", (int)m_Weather); - Int64 TimeOfDay = IniFile.GetValueSetI("General", "TimeInTicks", m_TimeOfDay); + m_TimeOfDay = IniFile.GetValueSetI("General", "TimeInTicks", m_TimeOfDay); if ((GetDimension() != dimNether) && (GetDimension() != dimEnd)) { -- cgit v1.2.3 From 3275bbf01b79eefb77861cca1fa4fd79c6ae1403 Mon Sep 17 00:00:00 2001 From: worktycho Date: Sat, 7 Jun 2014 00:10:58 +0100 Subject: Fix reading 64 bit values --- lib/inifile/iniFile.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/inifile/iniFile.cpp b/lib/inifile/iniFile.cpp index 7515483df..0c208b953 100644 --- a/lib/inifile/iniFile.cpp +++ b/lib/inifile/iniFile.cpp @@ -449,7 +449,7 @@ bool cIniFile::SetValueI(const AString & a_KeyName, const AString & a_ValueName, bool cIniFile::SetValueI(const AString & a_Keyname, const AString & a_ValueName, const Int64 a_Value, const bool a_CreateIfNotExists) { - return SetValue(a_Keyname, a_ValueName, Printf("lld", a_Value), a_CreateIfNotExists); + return SetValue(a_Keyname, a_ValueName, Printf("%lld", a_Value), a_CreateIfNotExists); } @@ -584,7 +584,10 @@ Int64 cIniFile::GetValueSetI(const AString & keyname, const AString & valuename, { AString Data; Printf(Data, "%lld", defValue); - return std::stoll(GetValueSet(keyname, valuename, Data)); + Astring resultstring = GetValueSet(keyname, valuename, Data); + Int64 result; + sscanf(resultstring.c_str(), "%lld", &result); + return result; } -- cgit v1.2.3 From b925eb4ad4fb02141915aa5392d8a0852f291355 Mon Sep 17 00:00:00 2001 From: worktycho Date: Sat, 7 Jun 2014 00:18:58 +0100 Subject: Capitalising --- lib/inifile/iniFile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/inifile/iniFile.cpp b/lib/inifile/iniFile.cpp index 0c208b953..66410b901 100644 --- a/lib/inifile/iniFile.cpp +++ b/lib/inifile/iniFile.cpp @@ -584,7 +584,7 @@ Int64 cIniFile::GetValueSetI(const AString & keyname, const AString & valuename, { AString Data; Printf(Data, "%lld", defValue); - Astring resultstring = GetValueSet(keyname, valuename, Data); + AString resultstring = GetValueSet(keyname, valuename, Data); Int64 result; sscanf(resultstring.c_str(), "%lld", &result); return result; -- cgit v1.2.3 From 35b79e5d710862f957bc494638a8d8906992665d Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Tue, 10 Jun 2014 20:43:27 +0100 Subject: Portal improvements and suggestions --- lib/inifile/iniFile.cpp | 4 ++ src/BlockID.cpp | 35 +++++++++++++ src/BlockID.h | 7 ++- src/Chunk.cpp | 15 +++++- src/Entities/Entity.cpp | 130 +++++++++++++++++++++++++++++++++--------------- src/Entities/Entity.h | 3 ++ src/Root.cpp | 6 +-- src/Root.h | 2 +- src/World.cpp | 18 +++++-- src/World.h | 13 ++++- 10 files changed, 179 insertions(+), 54 deletions(-) diff --git a/lib/inifile/iniFile.cpp b/lib/inifile/iniFile.cpp index 66410b901..30f93e5a3 100644 --- a/lib/inifile/iniFile.cpp +++ b/lib/inifile/iniFile.cpp @@ -586,7 +586,11 @@ Int64 cIniFile::GetValueSetI(const AString & keyname, const AString & valuename, Printf(Data, "%lld", defValue); AString resultstring = GetValueSet(keyname, valuename, Data); Int64 result; +#ifdef _WIN32 + sscanf_s(resultstring.c_str(), "%lld", &result); +#else sscanf(resultstring.c_str(), "%lld", &result); +#endif return result; } diff --git a/src/BlockID.cpp b/src/BlockID.cpp index bfe826f40..641a6a225 100644 --- a/src/BlockID.cpp +++ b/src/BlockID.cpp @@ -345,6 +345,41 @@ eDimension StringToDimension(const AString & a_DimensionString) +AString DimensionToString(eDimension a_Dimension) +{ + // Decode using a built-in map: + static struct + { + eDimension m_Dimension; + const char * m_String; + } DimensionMap[] = + { + { dimOverworld, "Overworld" }, + { dimOverworld, "Normal" }, + { dimOverworld, "World" }, + { dimNether, "Nether" }, + { dimNether, "Hell" }, // Alternate name for Nether + { dimEnd, "End" }, + { dimEnd, "Sky" }, // Old name for End + }; + + for (size_t i = 0; i < ARRAYCOUNT(DimensionMap); i++) + { + if (DimensionMap[i].m_Dimension == a_Dimension) + { + return DimensionMap[i].m_String; + } + } // for i - DimensionMap[] + + // Not found + LOGWARNING("Unknown dimension: \"%i\". Setting to Overworld", (int)a_Dimension); + return "Overworld"; +} + + + + + /// Translates damage type constant to a string representation (built-in). AString DamageTypeToString(eDamageType a_DamageType) { diff --git a/src/BlockID.h b/src/BlockID.h index a227245aa..97c1aae86 100644 --- a/src/BlockID.h +++ b/src/BlockID.h @@ -916,9 +916,14 @@ extern AString ItemToFullString(const cItem & a_Item); /// Translates a mob string ("ocelot") to mobtype (E_ENTITY_TYPE_OCELOT) extern int StringToMobType(const AString & a_MobString); -/// Translates a dimension string to dimension enum. Takes either a number or a dimension alias (built-in). Returns -1000 on failure +/// Translates a dimension string to dimension enum. Takes either a number or a dimension alias (built-in). Returns dimOverworld on failure extern eDimension StringToDimension(const AString & a_DimensionString); +/** Translates a dimension enum to dimension string. +Takes a string and returns "Overworld" on failure +*/ +extern AString DimensionToString(eDimension a_Dimension); + /// Translates damage type constant to a string representation (built-in). extern AString DamageTypeToString(eDamageType a_DamageType); diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 2850dd93b..02857ba5a 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -1859,7 +1859,20 @@ void cChunk::AddEntity(cEntity * a_Entity) MarkDirty(); } - ASSERT(std::find(m_Entities.begin(), m_Entities.end(), a_Entity) == m_Entities.end()); // Not there already + if (std::find(m_Entities.begin(), m_Entities.end(), a_Entity) != m_Entities.end()) + { + // Not there already + std::vector::iterator itr = std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), a_Entity->GetUniqueID()); + if (itr != m_EntitiesToRemove.end()) + { + m_EntitiesToRemove.erase(itr); + return; + } + else + { + ASSERT(!"Entity already present when AddEntity was called!"); + } + } m_Entities.push_back(a_Entity); } diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 2d8f385cb..4b376a1fe 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -12,6 +12,7 @@ #include "../Bindings/PluginManager.h" #include "../Tracer.h" #include "Player.h" +#include "BlockArea.h" @@ -1047,6 +1048,28 @@ void cEntity::DetectPortal() return; } + class cPortalChunkLoader : public cChunkStay + { + public: + cPortalChunkLoader(cEntity * a_Entity, Vector3i & a_PortalPos) : + m_Entity(a_Entity), + m_PortalPos(a_PortalPos) + {} + + private: + virtual bool OnAllChunksAvailable(void) override + { + m_Entity->CreateExitPortal(m_PortalPos.x, m_PortalPos.y, m_PortalPos.z); + return true; + } + + virtual void OnChunkAvailable(int a_ChunkX, int a_ChunkZ) override {}; + virtual void OnDisabled(void) override {}; + + cEntity * m_Entity; + Vector3i m_PortalPos; + }; + int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT; if ((Y > 0) && (Y < cChunkDef::Height)) { @@ -1061,31 +1084,31 @@ void cEntity::DetectPortal() switch (GetWorld()->GetDimension()) { - case dimNether: + case dimNether: MoveToWorld(GetWorld()->GetLinkedOverworldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName())); break; + case dimOverworld: { - cIniFile OwnIni; - OwnIni.ReadFile(GetWorld()->GetIniFileName()); - AString OverworldName = OwnIni.GetValue("General", "OverworldName", cRoot::Get()->GetDefaultWorld()->GetName()); + if (IsPlayer()) + { + ((cPlayer *)this)->AwardAchievement(achEnterPortal); + } + MoveToWorld(GetWorld()->GetNetherWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName(), dimNether, GetWorld()->GetName())); + + cChunkStay * Stay = new cPortalChunkLoader(this, Vector3i(X, Y, Z)); - cFile::CreateFolder(FILE_IO_PREFIX + OverworldName); - cIniFile File; - File.ReadFile(OverworldName + "/world.ini"); - File.SetValue("General", "Dimension", "Overworld"); - File.WriteFile(OverworldName + "/world.ini"); + int MinChunkX, MaxChunkX; + int MinChunkZ, MaxChunkZ; + cChunkDef::BlockToChunk(X - 128, Z - 128, MinChunkX, MinChunkZ); + cChunkDef::BlockToChunk(X + 128, Z + 128, MaxChunkX, MaxChunkZ); - MoveToWorld(OverworldName, cRoot::Get()->CreateAndInitializeWorld(OverworldName)); - break; - } - case dimOverworld: - { - cFile::CreateFolder(FILE_IO_PREFIX + GetWorld()->GetNetherWorldName()); - cIniFile File; - File.ReadFile(GetWorld()->GetNetherWorldName() + "/world.ini"); - File.SetValue("General", "Dimension", "Nether"); - File.SetValue("General", "OverworldName", GetWorld()->GetName()); - File.WriteFile(GetWorld()->GetNetherWorldName() + "/world.ini"); - - MoveToWorld(GetWorld()->GetNetherWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName())); + for (int OtherMinChunkX = MinChunkX; OtherMinChunkX <= MaxChunkX; ++OtherMinChunkX) + { + for (int OtherMinChunkZ = MinChunkZ; OtherMinChunkZ <= MaxChunkZ; ++OtherMinChunkZ) + { + Stay->Add(OtherMinChunkX, OtherMinChunkZ); + } + } + + Stay->Enable(*GetWorld()->GetChunkMap()); break; } default: break; @@ -1103,17 +1126,7 @@ void cEntity::DetectPortal() { case dimEnd: { - cIniFile OwnIni; - OwnIni.ReadFile(GetWorld()->GetIniFileName()); - AString OverworldName = OwnIni.GetValue("General", "OverworldName", cRoot::Get()->GetDefaultWorld()->GetName()); - - cFile::CreateFolder(FILE_IO_PREFIX + OverworldName); - cIniFile File; - File.ReadFile(OverworldName + "/world.ini"); - File.SetValue("General", "Dimension", "Overworld"); - File.WriteFile(OverworldName + "/world.ini"); - - MoveToWorld(OverworldName, cRoot::Get()->CreateAndInitializeWorld(OverworldName)); + MoveToWorld(GetWorld()->GetLinkedOverworldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName())); if (IsPlayer()) { @@ -1124,14 +1137,11 @@ void cEntity::DetectPortal() } case dimOverworld: { - cFile::CreateFolder(FILE_IO_PREFIX + GetWorld()->GetEndWorldName()); - cIniFile File; - File.ReadFile(GetWorld()->GetEndWorldName() + "/world.ini"); - File.SetValue("General", "Dimension", "End"); - File.SetValue("General", "OverworldName", GetWorld()->GetName()); - File.WriteFile(GetWorld()->GetEndWorldName() + "/world.ini"); - - MoveToWorld(GetWorld()->GetEndWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName())); + if (IsPlayer()) + { + ((cPlayer *)this)->AwardAchievement(achEnterTheEnd); + } + MoveToWorld(GetWorld()->GetEndWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName(), dimEnd, GetWorld()->GetName())); break; } default: break; @@ -1146,6 +1156,44 @@ void cEntity::DetectPortal() +void cEntity::CreateExitPortal(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + cBlockArea Area; + Area.Read(GetWorld(), a_BlockX - 128, a_BlockX + 128, 0, 128, a_BlockZ - 128, a_BlockZ + 128); + for (int x = a_BlockX - 128; x <= a_BlockX + 128; ++x) for (int y = 0; y <= 128; ++y) for (int z = a_BlockZ - 128; z <= a_BlockZ + 128; ++z) + { + if ( + (Area.GetBlockType(x, y, z) == E_BLOCK_NETHER_PORTAL) && + ( + (Area.GetBlockType(x, (int)floor(y + GetHeight()), z) == E_BLOCK_NETHER_PORTAL) || + (Area.GetBlockType(x, (int)floor(y - GetHeight()), z) == E_BLOCK_NETHER_PORTAL) + ) + ) + { + TeleportToCoords(x, y, z); + return; + } + } + + int MinX = std::max(a_BlockX - (int)ceil(GetWidth()), a_BlockX - 2), MaxX = std::max(a_BlockX + (int)ceil(GetWidth()), a_BlockX + 1); + int MinY = std::max(a_BlockY - (int)ceil(GetHeight()), a_BlockY - 2), MaxY = std::max(a_BlockY + (int)ceil(GetHeight()), a_BlockY + 1); + + for (int y = MinY; y < MaxY + 1; y += MaxY - MinY) for (int x = MinX; x < MaxX + 1; ++x) + { + Area.SetBlockType(x, y, a_BlockZ, E_BLOCK_OBSIDIAN); + } + for (int y = MinY; y < MaxY + 1; ++y) for (int x = MinX; x < MaxX + 1; x += MaxX - MinX) + { + Area.SetBlockType(x, y, a_BlockZ, E_BLOCK_OBSIDIAN); + } + + Area.Write(GetWorld(), MinX, MinY, a_BlockZ); +} + + + + + bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World) { cWorld * World; diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index da8256606..b2317aaac 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -335,6 +335,9 @@ public: /// Called when the entity finishes burning virtual void OnFinishedBurning(void); + + /** Creates exit portal at given coordinates */ + void CreateExitPortal(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_begin diff --git a/src/Root.cpp b/src/Root.cpp index 2a80baeb3..572cbf1fc 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -314,15 +314,15 @@ void cRoot::LoadWorlds(cIniFile & IniFile) -cWorld * cRoot::CreateAndInitializeWorld(const AString & a_WorldName) +cWorld * cRoot::CreateAndInitializeWorld(const AString & a_WorldName, eDimension a_Dimension, const AString & a_OverworldName) { if (m_WorldsByName[a_WorldName] != NULL) { return NULL; } - cWorld * NewWorld = new cWorld(a_WorldName.c_str()); + cWorld * NewWorld = new cWorld(a_WorldName.c_str(), a_Dimension, a_OverworldName); m_WorldsByName[a_WorldName] = NewWorld; - NewWorld->Start(); + NewWorld->Start(!a_OverworldName.empty()); NewWorld->InitializeSpawn(); m_PluginManager->CallHookWorldStarted(*NewWorld); return NewWorld; diff --git a/src/Root.h b/src/Root.h index d2a4d1eed..1b56b4528 100644 --- a/src/Root.h +++ b/src/Root.h @@ -44,7 +44,7 @@ public: cServer * GetServer(void) { return m_Server; } // tolua_export cWorld * GetDefaultWorld(void); // tolua_export cWorld * GetWorld(const AString & a_WorldName); // tolua_export - cWorld * CreateAndInitializeWorld(const AString & a_WorldName); // tolua_export + cWorld * CreateAndInitializeWorld(const AString & a_WorldName, eDimension a_Dimension = dimOverworld, const AString & a_OverworldName = ""); // tolua_export /// Calls the callback for each world; returns true if the callback didn't abort (return true) bool ForEachWorld(cWorldListCallback & a_Callback); // >> Exported in ManualBindings << diff --git a/src/World.cpp b/src/World.cpp index 1b5582b81..1f4a88fa0 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -232,7 +232,7 @@ void cWorld::cTickThread::Execute(void) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cWorld: -cWorld::cWorld(const AString & a_WorldName) : +cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AString & a_OverworldName) : m_WorldName(a_WorldName), m_IniFileName(m_WorldName + "/world.ini"), m_StorageSchema("Default"), @@ -253,7 +253,9 @@ cWorld::cWorld(const AString & a_WorldName) : m_Scoreboard(this), m_MapManager(this), m_GeneratorCallbacks(*this), - m_TickThread(*this) + m_TickThread(*this), + m_Dimension(a_Dimension), + m_OverworldName(a_OverworldName) { LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str()); @@ -511,7 +513,7 @@ void cWorld::InitializeSpawn(void) -void cWorld::Start(void) +void cWorld::Start(bool a_WasDimensionSet) { m_SpawnX = 0; m_SpawnY = cChunkDef::Height; @@ -523,8 +525,10 @@ void cWorld::Start(void) { LOGWARNING("Cannot read world settings from \"%s\", defaults will be used.", m_IniFileName.c_str()); } - AString Dimension = IniFile.GetValueSet("General", "Dimension", "Overworld"); + + AString Dimension = IniFile.GetValueSet("General", "Dimension", a_WasDimensionSet ? DimensionToString(GetDimension()) : "Overworld"); m_Dimension = StringToDimension(Dimension); + m_OverworldName = IniFile.GetValue("General", "OverworldName", a_WasDimensionSet ? m_OverworldName : ""); // Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found int KeyNum = IniFile.FindKey("SpawnPosition"); @@ -570,7 +574,7 @@ void cWorld::Start(void) m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true); int GameMode = IniFile.GetValueSetI("General", "Gamemode", (int)m_GameMode); int Weather = IniFile.GetValueSetI("General", "Weather", (int)m_Weather); - m_TimeOfDay = IniFile.GetValueSetI("General", "TimeInTicks", m_TimeOfDay); + m_TimeOfDay = IniFile.GetValueSetI("General", "TimeInTicks", m_TimeOfDay); if ((GetDimension() != dimNether) && (GetDimension() != dimEnd)) { @@ -759,6 +763,10 @@ void cWorld::Stop(void) IniFile.SetValueB("General", "EndPortalsEnabled", m_bEndPortalsEnabled); IniFile.SetValue("General", "EndWorldName", m_EndWorldName); } + else + { + IniFile.SetValue("General", "OverworldName", m_OverworldName); + } IniFile.SetValueI("Physics", "TNTShrapnelLevel", (int)m_TNTShrapnelLevel); IniFile.SetValueB("Mechanics", "CommandBlocksEnabled", m_bCommandBlocksEnabled); IniFile.SetValueB("Mechanics", "UseChatPrefixes", m_bUseChatPrefixes); diff --git a/src/World.h b/src/World.h index 80f69f22f..676c5d69a 100644 --- a/src/World.h +++ b/src/World.h @@ -636,6 +636,9 @@ public: AString GetEndWorldName(void) const { return m_EndWorldName; } void SetEndWorldName(const AString & a_Name) { m_EndWorldName = a_Name; } + + AString GetLinkedOverworldName(void) const { return m_OverworldName; } + void SetLinkedOverworldName(const AString & a_Name) { m_OverworldName = a_Name; } // tolua_end @@ -679,7 +682,7 @@ public: void InitializeSpawn(void); /** Starts threads that belong to this world */ - void Start(void); + void Start(bool a_WasDimensionSet = true); /** Stops threads that belong to this world (part of deinit) */ void Stop(void); @@ -816,6 +819,12 @@ private: AString m_WorldName; + + /** The name of the world that a portal in this world should link to + Only has effect if this world is a nether or end world, as it is used by entities to see which world to teleport to when in a portal + */ + AString m_OverworldName; + AString m_IniFileName; /** Name of the storage schema used to load and save chunks */ @@ -953,7 +962,7 @@ private: cClientHandleList m_ClientsToAdd; - cWorld(const AString & a_WorldName); + cWorld(const AString & a_WorldName, eDimension a_Dimension = dimOverworld, const AString & a_OverworldName = ""); virtual ~cWorld(); void Tick(float a_Dt, int a_LastTickDurationMSec); -- cgit v1.2.3 From 29567c56107c86b70da130f995564beb2eaf424c Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Thu, 12 Jun 2014 15:21:07 +0100 Subject: Portals animate and delay correctly --- MCServer/furnace.txt | 2 +- src/Chunk.cpp | 74 ++++++++++------------ src/Chunk.h | 2 +- src/ChunkMap.cpp | 1 + src/ClientHandle.cpp | 7 +-- src/ClientHandle.h | 2 +- src/Entities/Entity.cpp | 121 +++++++++++++++++++++++++++--------- src/Entities/Entity.h | 10 ++- src/Entities/Player.cpp | 21 ++----- src/Entities/Player.h | 10 +-- src/Protocol/Protocol.h | 2 +- src/Protocol/Protocol125.cpp | 8 +-- src/Protocol/Protocol125.h | 2 +- src/Protocol/Protocol16x.cpp | 4 +- src/Protocol/Protocol16x.h | 2 +- src/Protocol/Protocol17x.cpp | 8 +-- src/Protocol/Protocol17x.h | 2 +- src/Protocol/ProtocolRecognizer.cpp | 4 +- src/Protocol/ProtocolRecognizer.h | 2 +- src/World.cpp | 9 ++- 20 files changed, 175 insertions(+), 118 deletions(-) diff --git a/MCServer/furnace.txt b/MCServer/furnace.txt index 1e98583ba..229a939ff 100644 --- a/MCServer/furnace.txt +++ b/MCServer/furnace.txt @@ -87,4 +87,4 @@ ! 271:1 = 200 # 1 Wooden Axe -> 10 sec ! 269:1 = 200 # 1 Wooden Shovel -> 10 sec ! 290:1 = 200 # 1 Wooden Hoe -> 10 sec -! 268:1 = 200 # 1 Wooden Sword -> 10 sec +! 268:1 = 200 # 1 Wooden Sword -> 10 sec \ No newline at end of file diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 399c8b9c7..c9e4f5411 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -85,7 +85,8 @@ cChunk::cChunk( m_NeighborZM(a_NeighborZM), m_NeighborZP(a_NeighborZP), m_WaterSimulatorData(a_World->GetWaterSimulator()->CreateChunkData()), - m_LavaSimulatorData (a_World->GetLavaSimulator ()->CreateChunkData()) + m_LavaSimulatorData (a_World->GetLavaSimulator ()->CreateChunkData()), + m_EntityTickIteratorData(std::make_pair(false, &m_Entities.end())) { if (a_NeighborXM != NULL) { @@ -576,26 +577,38 @@ void cChunk::Tick(float a_Dt) } // Tick all entities in this chunk (except mobs): - for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) + m_EntityTickIteratorData.first = true; + for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) { - // Mobs are tickes inside MobTick (as we don't have to tick them if they are far away from players) + // Mobs are ticked inside cWorld::TickMobs() (as we don't have to tick them if they are far away from players) // Don't tick things queued to be removed - if ( - !((*itr)->IsMob()) && - (std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), (*itr)->GetUniqueID()) == m_EntitiesToRemove.end()) - ) + if (!((*itr)->IsMob())) { + m_EntityTickIteratorData.second = &itr; (*itr)->Tick(a_Dt, *this); + + if (itr != *m_EntityTickIteratorData.second) + { + itr = *m_EntityTickIteratorData.second; + } + else + { + ++itr; + } + continue; } + ++itr; } // for itr - m_Entitites[] + m_EntityTickIteratorData.first = false; for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) { - std::vector::iterator itr2 = std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), (*itr)->GetUniqueID()); - if (itr2 != m_EntitiesToRemove.end()) + if ((*itr)->IsDestroyed()) // Remove all entities that were scheduled for removal: { + LOGD("Destroying entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass()); + cEntity * ToDelete = *itr; itr = m_Entities.erase(itr); - m_EntitiesToRemove.erase(itr2); + delete ToDelete; } else if ( // If any entity moved out of the chunk, move it to the neighbor: ((*itr)->GetChunkX() != m_PosX) || @@ -607,17 +620,7 @@ void cChunk::Tick(float a_Dt) } else { - if ((*itr)->IsDestroyed()) // Remove all entities that were scheduled for removal: - { - LOGD("Destroying entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass()); - cEntity * ToDelete = *itr; - itr = m_Entities.erase(itr); - delete ToDelete; - } - else - { - ++itr; - } + ++itr; } } // for itr - m_Entitites[] @@ -1860,20 +1863,7 @@ void cChunk::AddEntity(cEntity * a_Entity) MarkDirty(); } - if (std::find(m_Entities.begin(), m_Entities.end(), a_Entity) != m_Entities.end()) - { - // Not there already - std::vector::iterator itr = std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), a_Entity->GetUniqueID()); - if (itr != m_EntitiesToRemove.end()) - { - m_EntitiesToRemove.erase(itr); - return; - } - else - { - ASSERT(!"Entity already present when AddEntity was called!"); - } - } + ASSERT(std::find(m_Entities.begin(), m_Entities.end(), a_Entity) == m_Entities.end()); m_Entities.push_back(a_Entity); } @@ -1884,7 +1874,14 @@ void cChunk::AddEntity(cEntity * a_Entity) void cChunk::RemoveEntity(cEntity * a_Entity) { - m_EntitiesToRemove.push_back(a_Entity->GetUniqueID()); + if (m_EntityTickIteratorData.first) + { + *m_EntityTickIteratorData.second = m_Entities.erase(*m_EntityTickIteratorData.second); + } + else + { + m_Entities.remove(a_Entity); + } // Mark as dirty if it was a server-generated entity: if (!a_Entity->IsPlayer()) @@ -1899,11 +1896,6 @@ void cChunk::RemoveEntity(cEntity * a_Entity) bool cChunk::HasEntity(int a_EntityID) { - if (std::find(m_EntitiesToRemove.begin(), m_EntitiesToRemove.end(), a_EntityID) != m_EntitiesToRemove.end()) - { - return false; // If EntitiesToRemove contains our ID, this chunk doesn't have it, as it should be removed soon - } - for (cEntityList::const_iterator itr = m_Entities.begin(), end = m_Entities.end(); itr != end; ++itr) { if ((*itr)->GetUniqueID() == a_EntityID) diff --git a/src/Chunk.h b/src/Chunk.h index 8123ac062..3046b2efe 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -425,7 +425,7 @@ private: // A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers cClientHandleList m_LoadedByClient; cEntityList m_Entities; - std::vector m_EntitiesToRemove; + std::pair m_EntityTickIteratorData; cBlockEntityList m_BlockEntities; /** Number of times the chunk has been requested to stay (by various cChunkStay objects); if zero, the chunk can be unloaded */ diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index dba6f3f41..d06b67b67 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -2398,6 +2398,7 @@ bool cChunkMap::ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinCh { for (int x = a_MinChunkX; x <= a_MaxChunkX; x++) { + LOG("Request %i %i", x, z); cChunkPtr Chunk = GetChunkNoLoad(x, ZERO_CHUNK_Y, z); if ((Chunk == NULL) || (!Chunk->IsValid())) { diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 256dad7da..84f096d67 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1766,8 +1766,7 @@ void cClientHandle::RemoveFromWorld(void) m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ); } // for itr - Chunks[] - // StreamChunks() called in cPlayer::MoveToWorld() after new world has been set - // Meanwhile here, we set last streamed values to bogus ones so everything is resent + // Here, we set last streamed values to bogus ones so everything is resent m_LastStreamedChunkX = 0x7fffffff; m_LastStreamedChunkZ = 0x7fffffff; m_HasSentPlayerChunk = false; @@ -2367,9 +2366,9 @@ void cClientHandle::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effec -void cClientHandle::SendRespawn(const cWorld & a_World) +void cClientHandle::SendRespawn(eDimension a_Dimension) { - m_Protocol->SendRespawn(a_World); + m_Protocol->SendRespawn(a_Dimension); } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 0d883f3af..99d10c3aa 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -149,7 +149,7 @@ public: void SendPlayerSpawn (const cPlayer & a_Player); void SendPluginMessage (const AString & a_Channel, const AString & a_Message); // Exported in ManualBindings.cpp void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID); - void SendRespawn (const cWorld & a_World); + void SendRespawn (eDimension a_Dimension); void SendExperience (void); void SendExperienceOrb (const cExpOrb & a_ExpOrb); void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode); diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 334cf5aa7..a7b6cca27 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1051,15 +1051,16 @@ void cEntity::DetectPortal() class cPortalChunkLoader : public cChunkStay { public: - cPortalChunkLoader(cEntity * a_Entity, Vector3i & a_PortalPos) : + cPortalChunkLoader(cEntity * a_Entity, cWorld & a_World, Vector3i & a_PortalPos) : m_Entity(a_Entity), - m_PortalPos(a_PortalPos) + m_PortalPos(a_PortalPos), + m_World(a_World) {} private: virtual bool OnAllChunksAvailable(void) override { - m_Entity->CreateExitPortal(m_PortalPos.x, m_PortalPos.y, m_PortalPos.z); + cEntity::CreateExitPortal(m_PortalPos.x, m_PortalPos.y, m_PortalPos.z, m_Entity->GetWidth(), m_Entity->GetHeight(), m_World, m_Entity->GetUniqueID()); return true; } @@ -1068,6 +1069,7 @@ void cEntity::DetectPortal() cEntity * m_Entity; Vector3i m_PortalPos; + cWorld & m_World; }; int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT; @@ -1077,106 +1079,167 @@ void cEntity::DetectPortal() { case E_BLOCK_NETHER_PORTAL: { - if (!GetWorld()->AreNetherPortalsEnabled()) + if (!GetWorld()->AreNetherPortalsEnabled() || m_PortalCooldownData.second) { return; } + if (m_PortalCooldownData.first != 80) + { + m_PortalCooldownData.first++; + return; + } + m_PortalCooldownData.first = 0; + switch (GetWorld()->GetDimension()) { - case dimNether: MoveToWorld(GetWorld()->GetLinkedOverworldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName())); break; + case dimNether: + { + m_PortalCooldownData.second = true; // Stop portals from working on respawn + + if (IsPlayer()) + { + ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimOverworld); + } + MoveToWorld(GetWorld()->GetLinkedOverworldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false); + + return; + } case dimOverworld: { + m_PortalCooldownData.second = true; // Stop portals from working on respawn + if (IsPlayer()) { ((cPlayer *)this)->AwardAchievement(achEnterPortal); + ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimNether); } - MoveToWorld(GetWorld()->GetNetherWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName(), dimNether, GetWorld()->GetName())); + MoveToWorld(GetWorld()->GetNetherWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName(), dimNether, GetWorld()->GetName()), false); - cChunkStay * Stay = new cPortalChunkLoader(this, Vector3i(X, Y, Z)); + cChunkStay * Stay = new cPortalChunkLoader(this, *cRoot::Get()->GetWorld(GetWorld()->GetNetherWorldName()), Vector3i(X, Y, Z)); int MinChunkX, MaxChunkX; int MinChunkZ, MaxChunkZ; cChunkDef::BlockToChunk(X - 128, Z - 128, MinChunkX, MinChunkZ); cChunkDef::BlockToChunk(X + 128, Z + 128, MaxChunkX, MaxChunkZ); - for (int OtherMinChunkX = MinChunkX; OtherMinChunkX <= MaxChunkX; ++OtherMinChunkX) + for (int ChunkX = MinChunkX; ChunkX <= MaxChunkX; ++ChunkX) { - for (int OtherMinChunkZ = MinChunkZ; OtherMinChunkZ <= MaxChunkZ; ++OtherMinChunkZ) + for (int ChunkZ = MinChunkZ; ChunkZ <= MaxChunkZ; ++ChunkZ) { - Stay->Add(OtherMinChunkX, OtherMinChunkZ); + LOG("Queue %i %i", ChunkX, ChunkZ); + Stay->Add(ChunkX, ChunkZ); } } Stay->Enable(*GetWorld()->GetChunkMap()); - break; + return; } default: break; } - break; + return; } case E_BLOCK_END_PORTAL: { - if (!GetWorld()->AreEndPortalsEnabled()) + if (!GetWorld()->AreEndPortalsEnabled() || m_PortalCooldownData.second) + { + return; + } + + if (m_PortalCooldownData.first != 80) { + m_PortalCooldownData.first++; return; } + m_PortalCooldownData.first = 0; switch (GetWorld()->GetDimension()) { case dimEnd: { - MoveToWorld(GetWorld()->GetLinkedOverworldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName())); + m_PortalCooldownData.second = true; // Stop portals from working on respawn if (IsPlayer()) { cPlayer * Player = (cPlayer *)this; Player->TeleportToCoords(Player->GetLastBedPos().x, Player->GetLastBedPos().y, Player->GetLastBedPos().z); + Player->GetClientHandle()->SendRespawn(dimOverworld); } - break; + MoveToWorld(GetWorld()->GetLinkedOverworldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false); + + return; } case dimOverworld: { + m_PortalCooldownData.second = true; // Stop portals from working on respawn + if (IsPlayer()) { ((cPlayer *)this)->AwardAchievement(achEnterTheEnd); + ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimEnd); } - MoveToWorld(GetWorld()->GetEndWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName(), dimEnd, GetWorld()->GetName())); - break; + MoveToWorld(GetWorld()->GetEndWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName(), dimEnd, GetWorld()->GetName()), false); + + return; } default: break; } + return; } default: break; } } + + // Allow portals to work again + m_PortalCooldownData.second = false; + m_PortalCooldownData.first = 0; } -void cEntity::CreateExitPortal(int a_BlockX, int a_BlockY, int a_BlockZ) +void cEntity::CreateExitPortal(int a_BlockX, int a_BlockY, int a_BlockZ, double a_EntityWidth, double a_EntityHeight, cWorld & a_World, int a_UniqueIDToTeleport) { cBlockArea Area; - Area.Read(GetWorld(), a_BlockX - 128, a_BlockX + 128, 0, 128, a_BlockZ - 128, a_BlockZ + 128); + Area.Read(&a_World, a_BlockX - 128, a_BlockX + 128, 0, 128, a_BlockZ - 128, a_BlockZ + 128); for (int x = a_BlockX - 128; x <= a_BlockX + 128; ++x) for (int y = 0; y <= 128; ++y) for (int z = a_BlockZ - 128; z <= a_BlockZ + 128; ++z) { if ( (Area.GetBlockType(x, y, z) == E_BLOCK_NETHER_PORTAL) && ( - (Area.GetBlockType(x, (int)floor(y + GetHeight()), z) == E_BLOCK_NETHER_PORTAL) || - (Area.GetBlockType(x, (int)floor(y - GetHeight()), z) == E_BLOCK_NETHER_PORTAL) + (Area.GetBlockType(x, (int)floor(y + a_EntityHeight), z) == E_BLOCK_NETHER_PORTAL) || + (Area.GetBlockType(x, (int)floor(y - a_EntityHeight), z) == E_BLOCK_NETHER_PORTAL) ) ) { - TeleportToCoords(x, y, z); + class cTeleportEntityToPortalCallback : public cEntityCallback + { + public: + cTeleportEntityToPortalCallback(int a_X, int a_Y, int a_Z) : + m_X(a_X), + m_Y(a_Y), + m_Z(a_Z) + {} + + virtual bool Item(cEntity * a_Entity) override + { + a_Entity->TeleportToCoords(m_X, m_Y, m_Z); + return true; + } + + private: + int m_X, m_Y, m_Z; + }; + + cTeleportEntityToPortalCallback TETPC(x, y, z); + a_World.DoWithEntityByID(a_UniqueIDToTeleport, TETPC); return; } } - int MinX = std::max(a_BlockX - (int)ceil(GetWidth()), a_BlockX - 2), MaxX = std::max(a_BlockX + (int)ceil(GetWidth()), a_BlockX + 1); - int MinY = std::max(a_BlockY - (int)ceil(GetHeight()), a_BlockY - 2), MaxY = std::max(a_BlockY + (int)ceil(GetHeight()), a_BlockY + 1); + int MinX = std::max(a_BlockX - (int)ceil(a_EntityWidth), a_BlockX - 2), MaxX = std::max(a_BlockX + (int)ceil(a_EntityWidth), a_BlockX + 1); + int MinY = std::max(a_BlockY - (int)ceil(a_EntityHeight), a_BlockY - 2), MaxY = std::max(a_BlockY + (int)ceil(a_EntityHeight), a_BlockY + 1); for (int y = MinY; y < MaxY + 1; y += MaxY - MinY) for (int x = MinX; x < MaxX + 1; ++x) { @@ -1187,15 +1250,17 @@ void cEntity::CreateExitPortal(int a_BlockX, int a_BlockY, int a_BlockZ) Area.SetBlockType(x, y, a_BlockZ, E_BLOCK_OBSIDIAN); } - Area.Write(GetWorld(), MinX, MinY, a_BlockZ); + Area.Write(&a_World, MinX, MinY, a_BlockZ); } -bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World) +bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World, bool a_ShouldSendRespawn) { + UNUSED(a_ShouldSendRespawn); + cWorld * World; if (a_World == NULL) { @@ -1213,6 +1278,7 @@ bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World) if (GetWorld() == World) { + // Don't move to same world return false; } @@ -1220,8 +1286,7 @@ bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World) GetWorld()->RemoveEntity(this); GetWorld()->BroadcastDestroyEntity(*this); - // Add to all the necessary parts of the new world - SetWorld(World); + // Queue add to new world World->AddEntity(this); return true; diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 934e0302b..4d922aa11 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -338,7 +338,7 @@ public: virtual void OnFinishedBurning(void); /** Creates exit portal at given coordinates */ - void CreateExitPortal(int a_BlockX, int a_BlockY, int a_BlockZ); + static void CreateExitPortal(int a_BlockX, int a_BlockY, int a_BlockZ, double a_EntityWidth, double a_EntityHeight, cWorld & a_World, int a_UniqueIDToTeleport); // tolua_begin @@ -374,7 +374,7 @@ public: virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ); /** Moves entity to specified world */ - virtual bool MoveToWorld(const AString & a_WorldName, cWorld * a_World = NULL); + virtual bool MoveToWorld(const AString & a_WorldName, cWorld * a_World = NULL, bool a_ShouldSendRespawn = true); // tolua_end @@ -510,6 +510,12 @@ protected: /** Air level of a mobile */ int m_AirLevel; int m_AirTickTimer; + + /** Portal delay timer and cooldown boolean + First value is to delay sending the repsawn packet (which triggers the Entering the {Dimension} screen). + Second value is to prevent a teleportation loop by ensuring we do not reenter a portal that we came out of. + */ + std::pair m_PortalCooldownData; private: /** Measured in degrees, [-180, +180) */ diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 4d6688694..a346e68cf 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -948,7 +948,7 @@ void cPlayer::Respawn(void) m_LifetimeTotalXp = 0; // ToDo: send score to client? How? - m_ClientHandle->SendRespawn(*GetWorld()); + m_ClientHandle->SendRespawn(GetWorld()->GetDimension()); // Extinguish the fire: StopBurning(); @@ -1570,7 +1570,7 @@ void cPlayer::TossItems(const cItems & a_Items) -bool cPlayer::MoveToWorld(const AString & a_WorldName, cWorld * a_World) +bool cPlayer::MoveToWorld(const AString & a_WorldName, cWorld * a_World, bool a_ShouldSendRespawn) { cWorld * World; if (a_World == NULL) @@ -1589,31 +1589,22 @@ bool cPlayer::MoveToWorld(const AString & a_WorldName, cWorld * a_World) if (GetWorld() == World) { + // Don't move to same world return false; } // Send the respawn packet: - if (m_ClientHandle != NULL) + if (a_ShouldSendRespawn && (m_ClientHandle != NULL)) { - m_ClientHandle->SendRespawn(*World); + m_ClientHandle->SendRespawn(World->GetDimension()); } - // Remove all links to the old world + // Remove player from old world m_World->RemovePlayer(this); - // If the dimension is different, we can send the respawn packet - // http://wiki.vg/Protocol#0x09 says "don't send if dimension is the same" as of 2013_07_02 - // Queue adding player to the new world, including all the necessary adjustments to the object World->AddPlayer(this); - if (GetWorld()->GetDimension() != World->GetDimension()) - { - GetClientHandle()->SendPlayerMoveLook(); - GetClientHandle()->SendHealth(); - GetClientHandle()->SendWholeInventory(*GetWindow()); - } - return true; } diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 99a0e601c..8f319f1ae 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -323,14 +323,14 @@ public: virtual void Killed(cEntity * a_Victim) override; - void Respawn(void); // tolua_export + void Respawn(void); // tolua_export - void SetVisible( bool a_bVisible ); // tolua_export - bool IsVisible(void) const { return m_bVisible; } // tolua_export + void SetVisible(bool a_bVisible); // tolua_export + bool IsVisible(void) const { return m_bVisible; } // tolua_export /** Moves the player to the specified world. Returns true if successful, false on failure (world not found). */ - virtual bool MoveToWorld(const AString & a_WorldName, cWorld * a_World = NULL) override; // tolua_export + virtual bool MoveToWorld(const AString & a_WorldName, cWorld * a_World = NULL, bool a_ShouldSendRespawn = true) override; // tolua_export /** Saves all player data, such as inventory, to JSON */ bool SaveToDisk(void); @@ -339,7 +339,7 @@ public: Takes a (NULL) cWorld pointer which it will assign a value to based on either the loaded world or default world */ bool LoadFromDisk(cWorld *& a_World); - void LoadPermissionsFromDisk(void); // tolua_export + void LoadPermissionsFromDisk(void); // tolua_export const AString & GetLoadedWorldName() { return m_LoadedWorldName; } diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index c6e569919..5b69d32a0 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -100,7 +100,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0; virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) = 0; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) = 0; - virtual void SendRespawn (const cWorld & a_World) = 0; + virtual void SendRespawn (eDimension a_Dimension) = 0; virtual void SendExperience (void) = 0; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) = 0; virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) = 0; diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp index 5796ba271..f33965cb9 100644 --- a/src/Protocol/Protocol125.cpp +++ b/src/Protocol/Protocol125.cpp @@ -833,23 +833,23 @@ void cProtocol125::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect -void cProtocol125::SendRespawn(const cWorld & a_World) +void cProtocol125::SendRespawn(eDimension a_Dimension) { cCSLock Lock(m_CSPacket); - if (m_LastSentDimension == a_World.GetDimension()) + if (m_LastSentDimension == a_Dimension) { // Must not send a respawn for the world with the same dimension, the client goes cuckoo if we do return; } cPlayer * Player = m_Client->GetPlayer(); WriteByte (PACKET_RESPAWN); - WriteInt ((int)(a_World.GetDimension())); + WriteInt ((int)(a_Dimension)); WriteByte (2); // TODO: Difficulty; 2 = Normal WriteChar ((char)Player->GetGameMode()); WriteShort (256); // Current world height WriteString("default"); Flush(); - m_LastSentDimension = a_World.GetDimension(); + m_LastSentDimension = a_Dimension; } diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index 85418f71f..dbf30a8e6 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -72,7 +72,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; - virtual void SendRespawn (const cWorld & a_World) override; + virtual void SendRespawn (eDimension a_Dimension) override; virtual void SendExperience (void) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; diff --git a/src/Protocol/Protocol16x.cpp b/src/Protocol/Protocol16x.cpp index 9e0f3f852..cc675c075 100644 --- a/src/Protocol/Protocol16x.cpp +++ b/src/Protocol/Protocol16x.cpp @@ -158,10 +158,10 @@ void cProtocol161::SendPlayerMaxSpeed(void) -void cProtocol161::SendRespawn(const cWorld & a_World) +void cProtocol161::SendRespawn(eDimension a_Dimension) { // Besides sending the respawn, we need to also send the player max speed, otherwise the client reverts to super-fast - super::SendRespawn(a_World); + super::SendRespawn(a_Dimension); SendPlayerMaxSpeed(); } diff --git a/src/Protocol/Protocol16x.h b/src/Protocol/Protocol16x.h index e91dc8a1c..2d50749ec 100644 --- a/src/Protocol/Protocol16x.h +++ b/src/Protocol/Protocol16x.h @@ -42,7 +42,7 @@ protected: virtual void SendGameMode (eGameMode a_GameMode) override; virtual void SendHealth (void) override; virtual void SendPlayerMaxSpeed(void) override; - virtual void SendRespawn (const cWorld & a_World) override; + virtual void SendRespawn (eDimension a_Dimension) override; virtual void SendWindowOpen (const cWindow & a_Window) override; virtual int ParseEntityAction (void) override; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index f5b176e54..2460a4914 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -986,9 +986,9 @@ void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect -void cProtocol172::SendRespawn(const cWorld & a_World) +void cProtocol172::SendRespawn(eDimension a_Dimension) { - if (m_LastSentDimension == a_World.GetDimension()) + if (m_LastSentDimension == a_Dimension) { // Must not send a respawn for the world with the same dimension, the client goes cuckoo if we do return; @@ -996,11 +996,11 @@ void cProtocol172::SendRespawn(const cWorld & a_World) cPacketizer Pkt(*this, 0x07); // Respawn packet cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteInt((int)a_World.GetDimension()); + Pkt.WriteInt((int)a_Dimension); Pkt.WriteByte(2); // TODO: Difficulty (set to Normal) Pkt.WriteByte((Byte)Player->GetEffectiveGameMode()); Pkt.WriteString("default"); - m_LastSentDimension = a_World.GetDimension(); + m_LastSentDimension = a_Dimension; } diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index 8be1d9211..5e3bf0e2a 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -104,7 +104,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; - virtual void SendRespawn (const cWorld & a_World) override; + virtual void SendRespawn (eDimension a_Dimension) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 virtual void SendExperience (void) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index 35a331f43..4b9d2e97a 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -555,10 +555,10 @@ void cProtocolRecognizer::SendRemoveEntityEffect(const cEntity & a_Entity, int a -void cProtocolRecognizer::SendRespawn(const cWorld & a_World) +void cProtocolRecognizer::SendRespawn(eDimension a_Dimension) { ASSERT(m_Protocol != NULL); - m_Protocol->SendRespawn(a_World); + m_Protocol->SendRespawn(a_Dimension); } diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index 5e178447c..eb83fb0c0 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -107,7 +107,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; - virtual void SendRespawn (const cWorld & a_World) override; + virtual void SendRespawn (eDimension a_Dimension) override; virtual void SendExperience (void) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; diff --git a/src/World.cpp b/src/World.cpp index 6904000ea..c86827080 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -2416,7 +2416,6 @@ void cWorld::AddPlayer(cPlayer * a_Player) void cWorld::RemovePlayer(cPlayer * a_Player) { - m_ChunkMap->RemoveEntity(a_Player); { cCSLock Lock(m_CSPlayersToAdd); @@ -2424,7 +2423,7 @@ void cWorld::RemovePlayer(cPlayer * a_Player) } { cCSLock Lock(m_CSPlayers); - LOGD("Removing player \"%s\" from world \"%s\".", a_Player->GetName().c_str(), m_WorldName.c_str()); + LOGD("Removing player %s from world \"%s\".", a_Player->GetName().c_str(), m_WorldName.c_str()); m_Players.remove(a_Player); } @@ -3213,7 +3212,8 @@ void cWorld::AddQueuedPlayers(void) for (cPlayerList::iterator itr = PlayersToAdd.begin(), end = PlayersToAdd.end(); itr != end; ++itr) { ASSERT(std::find(m_Players.begin(), m_Players.end(), *itr) == m_Players.end()); // Is it already in the list? HOW? - + + LOGD("Adding player %s to world \"%s\".", (*itr)->GetName().c_str(), m_WorldName.c_str()); m_Players.push_back(*itr); (*itr)->SetWorld(this); @@ -3242,6 +3242,9 @@ void cWorld::AddQueuedPlayers(void) if (Client != NULL) { Client->StreamChunks(); + Client->SendPlayerMoveLook(); + Client->SendHealth(); + Client->SendWholeInventory(*(*itr)->GetWindow()); } } // for itr - PlayersToAdd[] } -- cgit v1.2.3 From e10940d57cf8500eb306e986d7cc2d79bca00467 Mon Sep 17 00:00:00 2001 From: worktycho Date: Thu, 12 Jun 2014 17:24:14 +0100 Subject: Fixed compile --- src/Entities/Entity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index a7b6cca27..1c8818fe5 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1051,7 +1051,7 @@ void cEntity::DetectPortal() class cPortalChunkLoader : public cChunkStay { public: - cPortalChunkLoader(cEntity * a_Entity, cWorld & a_World, Vector3i & a_PortalPos) : + cPortalChunkLoader(cEntity * a_Entity, cWorld & a_World, const Vector3i & a_PortalPos) : m_Entity(a_Entity), m_PortalPos(a_PortalPos), m_World(a_World) -- cgit v1.2.3 From 93d4a8aa92af58bb073f18c87167358d18632899 Mon Sep 17 00:00:00 2001 From: Tycho Date: Thu, 12 Jun 2014 18:51:33 +0100 Subject: Removed unnessicary indirection from Entity iterator list --- src/Chunk.cpp | 10 +++++----- src/Chunk.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Chunk.cpp b/src/Chunk.cpp index c9e4f5411..7ca0a4afd 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -86,7 +86,7 @@ cChunk::cChunk( m_NeighborZP(a_NeighborZP), m_WaterSimulatorData(a_World->GetWaterSimulator()->CreateChunkData()), m_LavaSimulatorData (a_World->GetLavaSimulator ()->CreateChunkData()), - m_EntityTickIteratorData(std::make_pair(false, &m_Entities.end())) + m_EntityTickIteratorData(std::make_pair(false, m_Entities.end())) { if (a_NeighborXM != NULL) { @@ -584,12 +584,12 @@ void cChunk::Tick(float a_Dt) // Don't tick things queued to be removed if (!((*itr)->IsMob())) { - m_EntityTickIteratorData.second = &itr; + m_EntityTickIteratorData.second = itr; (*itr)->Tick(a_Dt, *this); - if (itr != *m_EntityTickIteratorData.second) + if (itr != m_EntityTickIteratorData.second) { - itr = *m_EntityTickIteratorData.second; + itr = m_EntityTickIteratorData.second; } else { @@ -1876,7 +1876,7 @@ void cChunk::RemoveEntity(cEntity * a_Entity) { if (m_EntityTickIteratorData.first) { - *m_EntityTickIteratorData.second = m_Entities.erase(*m_EntityTickIteratorData.second); + m_EntityTickIteratorData.second = m_Entities.erase(m_EntityTickIteratorData.second); } else { diff --git a/src/Chunk.h b/src/Chunk.h index 3046b2efe..1619df333 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -425,7 +425,7 @@ private: // A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers cClientHandleList m_LoadedByClient; cEntityList m_Entities; - std::pair m_EntityTickIteratorData; + std::pair m_EntityTickIteratorData; cBlockEntityList m_BlockEntities; /** Number of times the chunk has been requested to stay (by various cChunkStay objects); if zero, the chunk can be unloaded */ -- cgit v1.2.3 From c82f4f6309f760186c43b4f32596c3e78a5725b7 Mon Sep 17 00:00:00 2001 From: Tycho Date: Thu, 12 Jun 2014 18:56:48 +0100 Subject: Fixed order of initalisation --- src/Chunk.cpp | 4 ++-- src/World.cpp | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 7ca0a4afd..8255fdcaf 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -71,6 +71,7 @@ cChunk::cChunk( m_IsDirty(false), m_IsSaving(false), m_HasLoadFailed(false), + m_EntityTickIteratorData(std::make_pair(false, m_Entities.end())), m_StayCount(0), m_PosX(a_ChunkX), m_PosY(a_ChunkY), @@ -85,8 +86,7 @@ cChunk::cChunk( m_NeighborZM(a_NeighborZM), m_NeighborZP(a_NeighborZP), m_WaterSimulatorData(a_World->GetWaterSimulator()->CreateChunkData()), - m_LavaSimulatorData (a_World->GetLavaSimulator ()->CreateChunkData()), - m_EntityTickIteratorData(std::make_pair(false, m_Entities.end())) + m_LavaSimulatorData (a_World->GetLavaSimulator ()->CreateChunkData()) { if (a_NeighborXM != NULL) { diff --git a/src/World.cpp b/src/World.cpp index c86827080..3ed2f5f13 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -234,6 +234,7 @@ void cWorld::cTickThread::Execute(void) cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AString & a_OverworldName) : m_WorldName(a_WorldName), + m_OverworldName(a_OverworldName), m_IniFileName(m_WorldName + "/world.ini"), m_StorageSchema("Default"), #ifdef __arm__ @@ -241,6 +242,7 @@ cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AStrin #else m_StorageCompressionFactor(6), #endif + m_Dimension(a_Dimension), m_IsSpawnExplicitlySet(false), m_WorldAgeSecs(0), m_TimeOfDaySecs(0), @@ -253,9 +255,8 @@ cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AStrin m_Scoreboard(this), m_MapManager(this), m_GeneratorCallbacks(*this), - m_TickThread(*this), - m_Dimension(a_Dimension), - m_OverworldName(a_OverworldName) + m_TickThread(*this) + { LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str()); -- cgit v1.2.3 From a70b8298b6ada8abead9ef2b292531407225c2d1 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 14 Jun 2014 10:14:04 +0100 Subject: Cauldrons check the heightmap --- src/Blocks/BlockCauldron.h | 6 +++++- src/Blocks/WorldInterface.h | 8 ++++---- src/World.h | 6 +++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Blocks/BlockCauldron.h b/src/Blocks/BlockCauldron.h index 5ec776df6..e0f86f4cb 100644 --- a/src/Blocks/BlockCauldron.h +++ b/src/Blocks/BlockCauldron.h @@ -61,8 +61,12 @@ public: virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { - if (IsBiomeNoDownfall(a_Chunk.GetBiomeAt(a_RelX, a_RelZ)) || !a_WorldInterface.IsWeatherWet()) + int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; + int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; + if (!a_WorldInterface.IsWeatherWetAt(BlockX, BlockZ) || (a_RelY != a_WorldInterface.GetHeight(BlockX, BlockZ))) { + // It's not raining at our current location or we do not have a direct view of the sky + // We cannot eat the rain :( return; } diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h index 7df82197e..e5638c16e 100644 --- a/src/Blocks/WorldInterface.h +++ b/src/Blocks/WorldInterface.h @@ -37,9 +37,9 @@ public: virtual void SetTimeOfDay(Int64 a_TimeOfDay) = 0; - /** Returns true if the current weather has any precipitation - rain or storm - Does not check if biome has no downfall, use cChunk::GetBiomeAt(RelX, RelZ) for that - */ - virtual bool IsWeatherWet(void) const = 0; + /** Returns true if it is raining, stormy or snowing at the specified location. This takes into account biomes. */ + virtual bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) = 0; + /** Returns the world height at the specified coords; waits for the chunk to get loaded / generated */ + virtual int GetHeight(int a_BlockX, int a_BlockZ) = 0; }; diff --git a/src/World.h b/src/World.h index ab36e0a9b..0592c78fc 100644 --- a/src/World.h +++ b/src/World.h @@ -180,7 +180,7 @@ public: virtual eDimension GetDimension(void) const { return m_Dimension; } /** Returns the world height at the specified coords; waits for the chunk to get loaded / generated */ - int GetHeight(int a_BlockX, int a_BlockZ); + virtual int GetHeight(int a_BlockX, int a_BlockZ); // tolua_end @@ -749,10 +749,10 @@ public: } /** Returns true if the current weather has any precipitation - rain, storm or snow */ - virtual bool IsWeatherWet(void) const { return !IsWeatherSunny(); } + bool IsWeatherWet(void) const { return !IsWeatherSunny(); } /** Returns true if it is raining, stormy or snowing at the specified location. This takes into account biomes. */ - bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) + virtual bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) { return (IsWeatherWet() && !IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); } -- cgit v1.2.3 From 8a80843ddf062b4a2df622d661628e4c77b9c399 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 14 Jun 2014 10:18:16 +0100 Subject: Reverted portal creation code It wasn't really working and needs more development --- src/Entities/Entity.cpp | 100 ------------------------------------------------ src/Entities/Entity.h | 3 -- 2 files changed, 103 deletions(-) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 1c8818fe5..d42c49abe 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -12,7 +12,6 @@ #include "../Bindings/PluginManager.h" #include "../Tracer.h" #include "Player.h" -#include "BlockArea.h" @@ -1048,30 +1047,6 @@ void cEntity::DetectPortal() return; } - class cPortalChunkLoader : public cChunkStay - { - public: - cPortalChunkLoader(cEntity * a_Entity, cWorld & a_World, const Vector3i & a_PortalPos) : - m_Entity(a_Entity), - m_PortalPos(a_PortalPos), - m_World(a_World) - {} - - private: - virtual bool OnAllChunksAvailable(void) override - { - cEntity::CreateExitPortal(m_PortalPos.x, m_PortalPos.y, m_PortalPos.z, m_Entity->GetWidth(), m_Entity->GetHeight(), m_World, m_Entity->GetUniqueID()); - return true; - } - - virtual void OnChunkAvailable(int a_ChunkX, int a_ChunkZ) override {}; - virtual void OnDisabled(void) override {}; - - cEntity * m_Entity; - Vector3i m_PortalPos; - cWorld & m_World; - }; - int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT; if ((Y > 0) && (Y < cChunkDef::Height)) { @@ -1115,24 +1090,7 @@ void cEntity::DetectPortal() ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimNether); } MoveToWorld(GetWorld()->GetNetherWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName(), dimNether, GetWorld()->GetName()), false); - - cChunkStay * Stay = new cPortalChunkLoader(this, *cRoot::Get()->GetWorld(GetWorld()->GetNetherWorldName()), Vector3i(X, Y, Z)); - - int MinChunkX, MaxChunkX; - int MinChunkZ, MaxChunkZ; - cChunkDef::BlockToChunk(X - 128, Z - 128, MinChunkX, MinChunkZ); - cChunkDef::BlockToChunk(X + 128, Z + 128, MaxChunkX, MaxChunkZ); - for (int ChunkX = MinChunkX; ChunkX <= MaxChunkX; ++ChunkX) - { - for (int ChunkZ = MinChunkZ; ChunkZ <= MaxChunkZ; ++ChunkZ) - { - LOG("Queue %i %i", ChunkX, ChunkZ); - Stay->Add(ChunkX, ChunkZ); - } - } - - Stay->Enable(*GetWorld()->GetChunkMap()); return; } default: break; @@ -1199,64 +1157,6 @@ void cEntity::DetectPortal() -void cEntity::CreateExitPortal(int a_BlockX, int a_BlockY, int a_BlockZ, double a_EntityWidth, double a_EntityHeight, cWorld & a_World, int a_UniqueIDToTeleport) -{ - cBlockArea Area; - Area.Read(&a_World, a_BlockX - 128, a_BlockX + 128, 0, 128, a_BlockZ - 128, a_BlockZ + 128); - for (int x = a_BlockX - 128; x <= a_BlockX + 128; ++x) for (int y = 0; y <= 128; ++y) for (int z = a_BlockZ - 128; z <= a_BlockZ + 128; ++z) - { - if ( - (Area.GetBlockType(x, y, z) == E_BLOCK_NETHER_PORTAL) && - ( - (Area.GetBlockType(x, (int)floor(y + a_EntityHeight), z) == E_BLOCK_NETHER_PORTAL) || - (Area.GetBlockType(x, (int)floor(y - a_EntityHeight), z) == E_BLOCK_NETHER_PORTAL) - ) - ) - { - class cTeleportEntityToPortalCallback : public cEntityCallback - { - public: - cTeleportEntityToPortalCallback(int a_X, int a_Y, int a_Z) : - m_X(a_X), - m_Y(a_Y), - m_Z(a_Z) - {} - - virtual bool Item(cEntity * a_Entity) override - { - a_Entity->TeleportToCoords(m_X, m_Y, m_Z); - return true; - } - - private: - int m_X, m_Y, m_Z; - }; - - cTeleportEntityToPortalCallback TETPC(x, y, z); - a_World.DoWithEntityByID(a_UniqueIDToTeleport, TETPC); - return; - } - } - - int MinX = std::max(a_BlockX - (int)ceil(a_EntityWidth), a_BlockX - 2), MaxX = std::max(a_BlockX + (int)ceil(a_EntityWidth), a_BlockX + 1); - int MinY = std::max(a_BlockY - (int)ceil(a_EntityHeight), a_BlockY - 2), MaxY = std::max(a_BlockY + (int)ceil(a_EntityHeight), a_BlockY + 1); - - for (int y = MinY; y < MaxY + 1; y += MaxY - MinY) for (int x = MinX; x < MaxX + 1; ++x) - { - Area.SetBlockType(x, y, a_BlockZ, E_BLOCK_OBSIDIAN); - } - for (int y = MinY; y < MaxY + 1; ++y) for (int x = MinX; x < MaxX + 1; x += MaxX - MinX) - { - Area.SetBlockType(x, y, a_BlockZ, E_BLOCK_OBSIDIAN); - } - - Area.Write(&a_World, MinX, MinY, a_BlockZ); -} - - - - - bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World, bool a_ShouldSendRespawn) { UNUSED(a_ShouldSendRespawn); diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 4d922aa11..9f3b06c29 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -336,9 +336,6 @@ public: /// Called when the entity finishes burning virtual void OnFinishedBurning(void); - - /** Creates exit portal at given coordinates */ - static void CreateExitPortal(int a_BlockX, int a_BlockY, int a_BlockZ, double a_EntityWidth, double a_EntityHeight, cWorld & a_World, int a_UniqueIDToTeleport); // tolua_begin -- cgit v1.2.3 From b2fbcaf1bf43ca1f0e6df48de8584149cbe50222 Mon Sep 17 00:00:00 2001 From: archshift Date: Sun, 15 Jun 2014 20:27:27 -0700 Subject: Implemented PR suggestions Furnace.txt: newline BlockID: removed extraneous dimension mapping cEntity: fixed typo cPlayer: WorldPtr typedef --- MCServer/furnace.txt | 3 ++- src/BlockID.cpp | 4 ---- src/Entities/Entity.h | 2 +- src/Entities/Player.cpp | 2 +- src/Entities/Player.h | 3 ++- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/MCServer/furnace.txt b/MCServer/furnace.txt index 229a939ff..d6177184b 100644 --- a/MCServer/furnace.txt +++ b/MCServer/furnace.txt @@ -87,4 +87,5 @@ ! 271:1 = 200 # 1 Wooden Axe -> 10 sec ! 269:1 = 200 # 1 Wooden Shovel -> 10 sec ! 290:1 = 200 # 1 Wooden Hoe -> 10 sec -! 268:1 = 200 # 1 Wooden Sword -> 10 sec \ No newline at end of file +! 268:1 = 200 # 1 Wooden Sword -> 10 sec + diff --git a/src/BlockID.cpp b/src/BlockID.cpp index 641a6a225..70cb801b6 100644 --- a/src/BlockID.cpp +++ b/src/BlockID.cpp @@ -355,12 +355,8 @@ AString DimensionToString(eDimension a_Dimension) } DimensionMap[] = { { dimOverworld, "Overworld" }, - { dimOverworld, "Normal" }, - { dimOverworld, "World" }, { dimNether, "Nether" }, - { dimNether, "Hell" }, // Alternate name for Nether { dimEnd, "End" }, - { dimEnd, "Sky" }, // Old name for End }; for (size_t i = 0; i < ARRAYCOUNT(DimensionMap); i++) diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 9f3b06c29..8975803a2 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -509,7 +509,7 @@ protected: int m_AirTickTimer; /** Portal delay timer and cooldown boolean - First value is to delay sending the repsawn packet (which triggers the Entering the {Dimension} screen). + First value is to delay sending the respawn packet (which triggers the Entering the {Dimension} screen). Second value is to prevent a teleportation loop by ensuring we do not reenter a portal that we came out of. */ std::pair m_PortalCooldownData; diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index a346e68cf..c26c18690 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1651,7 +1651,7 @@ void cPlayer::LoadPermissionsFromDisk() -bool cPlayer::LoadFromDisk(cWorld *& a_World) +bool cPlayer::LoadFromDisk(cWorldPtr & a_World) { a_World = cRoot::Get()->GetWorld(GetLoadedWorldName()); if (a_World == NULL) diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 8f319f1ae..b1fef1b68 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -335,10 +335,11 @@ public: /** Saves all player data, such as inventory, to JSON */ bool SaveToDisk(void); + typedef cWorld * cWorldPtr; /** Loads player data from JSON to the object Takes a (NULL) cWorld pointer which it will assign a value to based on either the loaded world or default world */ - bool LoadFromDisk(cWorld *& a_World); + bool LoadFromDisk(cWorldPtr & a_World); void LoadPermissionsFromDisk(void); // tolua_export const AString & GetLoadedWorldName() { return m_LoadedWorldName; } -- cgit v1.2.3 From 1296c5dce71f59f1d7b2bfd1791a22daa26f2cb3 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 21 Jun 2014 20:42:10 +0100 Subject: More suggestions --- src/Entities/Entity.cpp | 2 +- src/Entities/Player.cpp | 2 +- src/Entities/Player.h | 6 ++++-- src/Mobs/Monster.cpp | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index d42c49abe..9110cd83b 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -869,7 +869,7 @@ void cEntity::TickBurning(cChunk & a_Chunk) // Remember the current burning state: bool HasBeenBurning = (m_TicksLeftBurning > 0); - if (IsBiomeNoDownfall(a_Chunk.GetBiomeAt(POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width, POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width)) || GetWorld()->IsWeatherWet()) + if (GetWorld()->IsWeatherWetAt(POSX_TOINT, POSZ_TOINT)) { if (POSY_TOINT > m_World->GetHeight(POSX_TOINT, POSZ_TOINT)) { diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index c26c18690..e975abdf5 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1599,7 +1599,7 @@ bool cPlayer::MoveToWorld(const AString & a_WorldName, cWorld * a_World, bool a_ m_ClientHandle->SendRespawn(World->GetDimension()); } - // Remove player from old world + // Remove player from the old world m_World->RemovePlayer(this); // Queue adding player to the new world, including all the necessary adjustments to the object diff --git a/src/Entities/Player.h b/src/Entities/Player.h index b1fef1b68..c72d1eb8d 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -350,7 +350,7 @@ public: void SendExperience(void); - /** In UI windows, the item that the player is dragging */ + /** In UI windows, get the item that the player is dragging */ cItem & GetDraggingItem(void) {return m_DraggingItem; } // In UI windows, when inventory-painting: @@ -398,7 +398,9 @@ public: /** If true the player can fly even when he's not in creative. */ void SetCanFly(bool a_CanFly); - /** Gets the last position that the player slept in */ + /** Gets the last position that the player slept in + This is initialised to the world spawn point if the player has not slept in a bed as of yet + */ Vector3i GetLastBedPos(void) const { return m_LastBedPos; } /** Sets the player's bed (home) position */ diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 0f030da2d..89329dace 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -1034,7 +1034,7 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk) (a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand (GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime !IsOnFire() && // Not already burning - (IsBiomeNoDownfall(a_Chunk.GetBiomeAt(RelX, RelZ)) || !GetWorld()->IsWeatherWet()) // Not raining + GetWorld()->IsWeatherWetAt(POSX_TOINT, POSZ_TOINT) // Not raining ) { // Burn for 100 ticks, then decide again -- cgit v1.2.3 From 6e681269d9dfb33b5b73f4f01a61def247b3aee7 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 21 Jun 2014 22:07:38 +0100 Subject: Fixed invalid iterators --- src/Chunk.cpp | 33 ++++++++++----------------------- src/Chunk.h | 1 - src/Entities/Entity.cpp | 3 ++- src/Entities/Entity.h | 10 +++++++++- src/Entities/Player.cpp | 1 + src/World.cpp | 14 ++++---------- src/World.h | 3 --- 7 files changed, 26 insertions(+), 39 deletions(-) diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 8255fdcaf..727eb451d 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -71,7 +71,6 @@ cChunk::cChunk( m_IsDirty(false), m_IsSaving(false), m_HasLoadFailed(false), - m_EntityTickIteratorData(std::make_pair(false, m_Entities.end())), m_StayCount(0), m_PosX(a_ChunkX), m_PosY(a_ChunkY), @@ -577,44 +576,39 @@ void cChunk::Tick(float a_Dt) } // Tick all entities in this chunk (except mobs): - m_EntityTickIteratorData.first = true; - for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) + for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) { // Mobs are ticked inside cWorld::TickMobs() (as we don't have to tick them if they are far away from players) // Don't tick things queued to be removed if (!((*itr)->IsMob())) { - m_EntityTickIteratorData.second = itr; (*itr)->Tick(a_Dt, *this); - - if (itr != m_EntityTickIteratorData.second) - { - itr = m_EntityTickIteratorData.second; - } - else - { - ++itr; - } continue; } - ++itr; } // for itr - m_Entitites[] - m_EntityTickIteratorData.first = false; for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) { if ((*itr)->IsDestroyed()) // Remove all entities that were scheduled for removal: { LOGD("Destroying entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass()); + MarkDirty(); cEntity * ToDelete = *itr; itr = m_Entities.erase(itr); delete ToDelete; } + else if ((*itr)->IsTravellingThroughPortal()) + { + MarkDirty(); + (*itr)->SetIsTravellingThroughPortal(false); + itr = m_Entities.erase(itr); + } else if ( // If any entity moved out of the chunk, move it to the neighbor: ((*itr)->GetChunkX() != m_PosX) || ((*itr)->GetChunkZ() != m_PosZ) ) { + MarkDirty(); MoveEntityToNewChunk(*itr); itr = m_Entities.erase(itr); } @@ -1874,14 +1868,7 @@ void cChunk::AddEntity(cEntity * a_Entity) void cChunk::RemoveEntity(cEntity * a_Entity) { - if (m_EntityTickIteratorData.first) - { - m_EntityTickIteratorData.second = m_Entities.erase(m_EntityTickIteratorData.second); - } - else - { - m_Entities.remove(a_Entity); - } + m_Entities.remove(a_Entity); // Mark as dirty if it was a server-generated entity: if (!a_Entity->IsPlayer()) diff --git a/src/Chunk.h b/src/Chunk.h index 1619df333..dfdabea04 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -425,7 +425,6 @@ private: // A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers cClientHandleList m_LoadedByClient; cEntityList m_Entities; - std::pair m_EntityTickIteratorData; cBlockEntityList m_BlockEntities; /** Number of times the chunk has been requested to stay (by various cChunkStay objects); if zero, the chunk can be unloaded */ diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 9110cd83b..9a8c6586d 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -57,6 +57,7 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d , m_Width(a_Width) , m_Height(a_Height) , m_InvulnerableTicks(0) + , m_IsTravellingThroughPortal(false) { cCSLock Lock(m_CSCount); m_EntityCount++; @@ -1183,7 +1184,7 @@ bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World, bool a_ } // Remove all links to the old world - GetWorld()->RemoveEntity(this); + SetIsTravellingThroughPortal(true); // cChunk handles entity removal GetWorld()->BroadcastDestroyEntity(*this); // Queue add to new world diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 8975803a2..0293968ab 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -374,6 +374,12 @@ public: virtual bool MoveToWorld(const AString & a_WorldName, cWorld * a_World = NULL, bool a_ShouldSendRespawn = true); // tolua_end + + /** Returns if the entity is travelling through a portal. Set to true by MoveToWorld and to false when the entity is removed by the old chunk */ + bool IsTravellingThroughPortal(void) const { return m_IsTravellingThroughPortal; } + + /** Sets if the entity has begun travelling through a portal or not */ + void SetIsTravellingThroughPortal(bool a_Flag) { m_IsTravellingThroughPortal = a_Flag; } /// Updates clients of changes in the entity. virtual void BroadcastMovementUpdate(const cClientHandle * a_Exclude = NULL); @@ -470,6 +476,9 @@ protected: /** True when entity is initialised (Initialize()) and false when destroyed pending deletion (Destroy()) */ bool m_IsInitialized; + /** True when entity is being moved across worlds, false anytime else */ + bool m_IsTravellingThroughPortal; + eEntityType m_EntityType; cWorld * m_World; @@ -492,7 +501,6 @@ protected: /// Time, in ticks, since the last damage dealt by the void. Reset to zero when moving out of the void. int m_TicksSinceLastVoidDamage; - virtual void Destroyed(void) {} // Called after the entity has been destroyed /** Called in each tick to handle air-related processing i.e. drowning */ diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index e975abdf5..b72f14f57 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1600,6 +1600,7 @@ bool cPlayer::MoveToWorld(const AString & a_WorldName, cWorld * a_World, bool a_ } // Remove player from the old world + SetIsTravellingThroughPortal(true); // cChunk handles entity removal m_World->RemovePlayer(this); // Queue adding player to the new world, including all the necessary adjustments to the object diff --git a/src/World.cpp b/src/World.cpp index 3ed2f5f13..c9199b6ba 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -2417,7 +2417,10 @@ void cWorld::AddPlayer(cPlayer * a_Player) void cWorld::RemovePlayer(cPlayer * a_Player) { - m_ChunkMap->RemoveEntity(a_Player); + if (!a_Player->IsTravellingThroughPortal()) + { + m_ChunkMap->RemoveEntity(a_Player); + } { cCSLock Lock(m_CSPlayersToAdd); m_PlayersToAdd.remove(a_Player); @@ -2919,15 +2922,6 @@ bool cWorld::HasEntity(int a_UniqueID) -void cWorld::RemoveEntity(cEntity * a_Entity) -{ - m_ChunkMap->RemoveEntity(a_Entity); -} - - - - - /* unsigned int cWorld::GetNumPlayers(void) { diff --git a/src/World.h b/src/World.h index 0592c78fc..1d9026a5d 100644 --- a/src/World.h +++ b/src/World.h @@ -313,9 +313,6 @@ public: bool HasEntity(int a_UniqueID); - /** Removes the entity, the entity ptr ownership is assumed taken by the caller */ - void RemoveEntity(cEntity * a_Entity); - /** Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true */ bool ForEachEntity(cEntityCallback & a_Callback); // Exported in ManualBindings.cpp -- cgit v1.2.3 From e709652257da1ba06a6642b4978365b14bc11a22 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 22 Jun 2014 00:21:39 +0100 Subject: Conforms to standards --- src/Entities/Entity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index fadd12135..d4edc9144 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -37,6 +37,7 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d , m_Gravity(-9.81f) , m_LastPos(a_X, a_Y, a_Z) , m_IsInitialized(false) + , m_IsTravellingThroughPortal(false) , m_EntityType(a_EntityType) , m_World(NULL) , m_IsFireproof(false) @@ -57,7 +58,6 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d , m_Width(a_Width) , m_Height(a_Height) , m_InvulnerableTicks(0) - , m_IsTravellingThroughPortal(false) { cCSLock Lock(m_CSCount); m_EntityCount++; -- cgit v1.2.3 From 719551c31f5ed0d3cbad9797dd81a6bf1ae4e5a2 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 18 Jul 2014 20:12:27 +0100 Subject: Fix failed merge and other issues --- src/ClientHandle.cpp | 4 ++-- src/ClientHandle.h | 2 +- src/Entities/Entity.cpp | 6 +++--- src/Entities/Player.cpp | 40 ++++++++------------------------------- src/Entities/Player.h | 11 +---------- src/Protocol/Protocol.h | 2 +- src/Protocol/Protocol125.cpp | 2 +- src/Protocol/Protocol125.h | 2 +- src/Protocol/Protocol16x.h | 2 +- src/Protocol/Protocol17x.cpp | 2 +- src/Protocol/Protocol17x.h | 2 +- src/Protocol/ProtocolRecognizer.h | 2 +- src/World.cpp | 16 ++++++---------- src/World.h | 12 ------------ 14 files changed, 28 insertions(+), 77 deletions(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 1a18649c9..f90da94dd 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -2375,9 +2375,9 @@ void cClientHandle::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effec -void cClientHandle::SendRespawn(eDimension a_Dimension) +void cClientHandle::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) { - m_Protocol->SendRespawn(a_Dimension); + m_Protocol->SendRespawn(a_Dimension, a_ShouldIgnoreDimensionChecks); } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index cb0471421..e3c2b590f 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -161,7 +161,7 @@ public: void SendPlayerSpawn (const cPlayer & a_Player); void SendPluginMessage (const AString & a_Channel, const AString & a_Message); // Exported in ManualBindings.cpp void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID); - void SendRespawn (eDimension a_Dimension); + void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks = false); void SendExperience (void); void SendExperienceOrb (const cExpOrb & a_ExpOrb); void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode); diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index e5e4cf4cb..bd1839580 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1028,7 +1028,7 @@ void cEntity::DetectCacti(void) void cEntity::DetectPortal() { - if (!GetWorld()->AreNetherPortalsEnabled() && !GetWorld()->AreEndPortalsEnabled()) + if (!GetWorld()->GetNetherWorldName().empty() && !GetWorld()->GetEndWorldName().empty()) { return; } @@ -1040,7 +1040,7 @@ void cEntity::DetectPortal() { case E_BLOCK_NETHER_PORTAL: { - if (!GetWorld()->AreNetherPortalsEnabled() || m_PortalCooldownData.second) + if (GetWorld()->GetNetherWorldName().empty() || m_PortalCooldownData.second) { return; } @@ -1085,7 +1085,7 @@ void cEntity::DetectPortal() } case E_BLOCK_END_PORTAL: { - if (!GetWorld()->AreEndPortalsEnabled() || m_PortalCooldownData.second) + if (GetWorld()->GetNetherWorldName().empty() || m_PortalCooldownData.second) { return; } diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 1acc8a962..2a91600e7 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1695,12 +1695,7 @@ void cPlayer::LoadPermissionsFromDisk() -<<<<<<< HEAD bool cPlayer::LoadFromDisk(cWorldPtr & a_World) -======= - -bool cPlayer::LoadFromDisk(void) ->>>>>>> master { a_World = cRoot::Get()->GetWorld(GetLoadedWorldName()); if (a_World == NULL) @@ -1711,7 +1706,7 @@ bool cPlayer::LoadFromDisk(void) LoadPermissionsFromDisk(); // Load from the UUID file: - if (LoadFromFile(GetUUIDFileName(m_UUID))) + if (LoadFromFile(GetUUIDFileName(m_UUID), a_World)) { return true; } @@ -1720,7 +1715,7 @@ bool cPlayer::LoadFromDisk(void) AString OfflineUUID = cClientHandle::GenerateOfflineUUID(GetName()); if (cRoot::Get()->GetServer()->ShouldLoadOfflinePlayerData()) { - if (LoadFromFile(GetUUIDFileName(OfflineUUID))) + if (LoadFromFile(GetUUIDFileName(OfflineUUID), a_World)) { return true; } @@ -1730,7 +1725,7 @@ bool cPlayer::LoadFromDisk(void) if (cRoot::Get()->GetServer()->ShouldLoadNamedPlayerData()) { AString OldStyleFileName = Printf("players/%s.json", GetName().c_str()); - if (LoadFromFile(OldStyleFileName)) + if (LoadFromFile(OldStyleFileName, a_World)) { // Save in new format and remove the old file if (SaveToDisk()) @@ -1752,7 +1747,7 @@ bool cPlayer::LoadFromDisk(void) -bool cPlayer::LoadFromFile(const AString & a_FileName) +bool cPlayer::LoadFromFile(const AString & a_FileName, cWorld * a_World) { // Load the data from the file: cFile f; @@ -1860,28 +1855,6 @@ bool cPlayer::SaveToDisk() cEnderChestEntity::SaveToJson(JSON_EnderChestInventory, m_EnderChestContents); Json::Value root; -<<<<<<< HEAD - root["position"] = JSON_PlayerPosition; - root["rotation"] = JSON_PlayerRotation; - root["inventory"] = JSON_Inventory; - root["health"] = m_Health; - root["xpTotal"] = m_LifetimeTotalXp; - root["xpCurrent"] = m_CurrentXp; - root["air"] = m_AirLevel; - root["food"] = m_FoodLevel; - root["foodSaturation"] = m_FoodSaturationLevel; - root["foodTickTimer"] = m_FoodTickTimer; - root["foodExhaustion"] = m_FoodExhaustionLevel; - root["world"] = GetWorld()->GetName(); - root["isflying"] = IsFlying(); - root["SpawnX"] = GetLastBedPos().x; - root["SpawnY"] = GetLastBedPos().y; - root["SpawnZ"] = GetLastBedPos().z; - - if (m_GameMode == GetWorld()->GetGameMode()) - { - root["gamemode"] = (int) eGameMode_NotSet; -======= root["position"] = JSON_PlayerPosition; root["rotation"] = JSON_PlayerRotation; root["inventory"] = JSON_Inventory; @@ -1896,6 +1869,10 @@ bool cPlayer::SaveToDisk() root["foodExhaustion"] = m_FoodExhaustionLevel; root["isflying"] = IsFlying(); root["lastknownname"] = GetName(); + root["SpawnX"] = GetLastBedPos().x; + root["SpawnY"] = GetLastBedPos().y; + root["SpawnZ"] = GetLastBedPos().z; + if (m_World != NULL) { root["world"] = m_World->GetName(); @@ -1907,7 +1884,6 @@ bool cPlayer::SaveToDisk() { root["gamemode"] = (int) m_GameMode; } ->>>>>>> master } else { diff --git a/src/Entities/Player.h b/src/Entities/Player.h index f84cc5f55..ad434f036 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -326,11 +326,6 @@ public: virtual void Killed(cEntity * a_Victim) override; - void Respawn(void); // tolua_export - - void SetVisible(bool a_bVisible); // tolua_export - bool IsVisible(void) const { return m_bVisible; } // tolua_export - void Respawn(void); // tolua_export void SetVisible( bool a_bVisible ); // tolua_export @@ -352,7 +347,7 @@ Takes a (NULL) cWorld pointer which it will assign a value to based on either th /** Loads the player data from the specified file. Returns true on success, false on failure. */ - bool LoadFromFile(const AString & a_FileName); + bool LoadFromFile(const AString & a_FileName, cWorld * a_World); void LoadPermissionsFromDisk(void); // tolua_export @@ -544,8 +539,6 @@ protected: cStatManager m_Stats; -<<<<<<< HEAD -======= /** Flag representing whether the player is currently in a bed Set by a right click on unoccupied bed, unset by a time fast forward or teleport */ bool m_bIsInBed; @@ -563,8 +556,6 @@ protected: If no ClientHandle is given, the UUID is initialized to empty. */ AString m_UUID; - ->>>>>>> master /** Sets the speed and sends it to the client, so that they are forced to move so. */ virtual void DoSetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ) override; diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index 7e9eed402..58dbfeff5 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -100,7 +100,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0; virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) = 0; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) = 0; - virtual void SendRespawn (eDimension a_Dimension) = 0; + virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) = 0; virtual void SendExperience (void) = 0; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) = 0; virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) = 0; diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp index 8cb34c128..320c1212c 100644 --- a/src/Protocol/Protocol125.cpp +++ b/src/Protocol/Protocol125.cpp @@ -836,7 +836,7 @@ void cProtocol125::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect void cProtocol125::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) { cCSLock Lock(m_CSPacket); - if ((m_LastSentDimension == a_World.GetDimension()) && !a_ShouldIgnoreDimensionChecks) + if ((m_LastSentDimension == a_Dimension) && !a_ShouldIgnoreDimensionChecks) { // Must not send a respawn for the world with the same dimension, the client goes cuckoo if we do (unless we are respawning from death) return; diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index 955e3e741..d1ed00b54 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -72,7 +72,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; - virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks = false) override; + virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) override; virtual void SendExperience (void) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; diff --git a/src/Protocol/Protocol16x.h b/src/Protocol/Protocol16x.h index 13866801a..add761d1e 100644 --- a/src/Protocol/Protocol16x.h +++ b/src/Protocol/Protocol16x.h @@ -42,7 +42,7 @@ protected: virtual void SendGameMode (eGameMode a_GameMode) override; virtual void SendHealth (void) override; virtual void SendPlayerMaxSpeed(void) override; - virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks = false) override; + virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) override; virtual void SendWindowOpen (const cWindow & a_Window) override; virtual int ParseEntityAction (void) override; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index a421e4da6..0ff0d0357 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -988,7 +988,7 @@ void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect void cProtocol172::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) { - if ((m_LastSentDimension == a_World.GetDimension()) && !a_ShouldIgnoreDimensionChecks) + if ((m_LastSentDimension == a_Dimension) && !a_ShouldIgnoreDimensionChecks) { // Must not send a respawn for the world with the same dimension, the client goes cuckoo if we do (unless we are respawning from death) return; diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index 2d4005f57..be41abd64 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -104,7 +104,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; - virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks = false) override; + virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) override; virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override; virtual void SendExperience (void) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index b78528e29..9c6c898ab 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -107,7 +107,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; - virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks = false) override; + virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) override; virtual void SendExperience (void) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; diff --git a/src/World.cpp b/src/World.cpp index e32771353..924d5adbb 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -527,7 +527,7 @@ void cWorld::Start(bool a_WasDimensionSet) AString Dimension = IniFile.GetValueSet("General", "Dimension", a_WasDimensionSet ? DimensionToString(GetDimension()) : "Overworld"); m_Dimension = StringToDimension(Dimension); - m_OverworldName = IniFile.GetValue("General", "OverworldName", a_WasDimensionSet ? m_OverworldName : ""); + m_OverworldName = IniFile.GetValue("LinkedWorlds", "OverworldName", a_WasDimensionSet ? m_OverworldName : ""); // Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found int KeyNum = IniFile.FindKey("SpawnPosition"); @@ -577,10 +577,8 @@ void cWorld::Start(bool a_WasDimensionSet) if ((GetDimension() != dimNether) && (GetDimension() != dimEnd)) { - m_bNetherPortalsEnabled = IniFile.GetValueSetB("General", "NetherPortalsEnabled", true); - m_NetherWorldName = IniFile.GetValueSet("General", "NetherWorldName", DEFAULT_NETHER_NAME); - m_bEndPortalsEnabled = IniFile.GetValueSetB("General", "EndPortalsEnabled", true); - m_EndWorldName = IniFile.GetValueSet("General", "EndWorldName", DEFAULT_END_NAME); + m_NetherWorldName = IniFile.GetValueSet("LinkedWorlds", "NetherWorldName", DEFAULT_NETHER_NAME); + m_EndWorldName = IniFile.GetValueSet("LinkedWorlds", "EndWorldName", DEFAULT_END_NAME); } // Adjust the enum-backed variables into their respective bounds: @@ -757,14 +755,12 @@ void cWorld::Stop(void) IniFile.ReadFile(m_IniFileName); if ((GetDimension() != dimNether) && (GetDimension() != dimEnd)) { - IniFile.SetValueB("General", "NetherPortalsEnabled", m_bNetherPortalsEnabled); - IniFile.SetValue("General", "NetherWorldName", m_NetherWorldName); - IniFile.SetValueB("General", "EndPortalsEnabled", m_bEndPortalsEnabled); - IniFile.SetValue("General", "EndWorldName", m_EndWorldName); + IniFile.SetValue("LinkedWorlds", "NetherWorldName", m_NetherWorldName); + IniFile.SetValue("LinkedWorlds", "EndWorldName", m_EndWorldName); } else { - IniFile.SetValue("General", "OverworldName", m_OverworldName); + IniFile.SetValue("LinkedWorlds", "OverworldName", m_OverworldName); } IniFile.SetValueI("Physics", "TNTShrapnelLevel", (int)m_TNTShrapnelLevel); IniFile.SetValueB("Mechanics", "CommandBlocksEnabled", m_bCommandBlocksEnabled); diff --git a/src/World.h b/src/World.h index 92376b4a0..73b8b81b0 100644 --- a/src/World.h +++ b/src/World.h @@ -630,12 +630,6 @@ public: bool ShouldUseChatPrefixes(void) const { return m_bUseChatPrefixes; } void SetShouldUseChatPrefixes(bool a_Flag) { m_bUseChatPrefixes = a_Flag; } - bool AreNetherPortalsEnabled(void) const { return m_bNetherPortalsEnabled; } - void SetNetherPortalsEnabled(bool a_Flag) { m_bNetherPortalsEnabled = a_Flag; } - - bool AreEndPortalsEnabled(void) const { return m_bEndPortalsEnabled; } - void SetEndPortalsEnabled(bool a_Flag) { m_bEndPortalsEnabled = a_Flag; } - AString GetNetherWorldName(void) const { return m_NetherWorldName; } void SetNetherWorldName(const AString & a_Name) { m_NetherWorldName = a_Name; } @@ -938,12 +932,6 @@ private: */ eShrapnelLevel m_TNTShrapnelLevel; - /** Whether nether portals teleport entities */ - bool m_bNetherPortalsEnabled; - - /** Whether end portals teleport entities */ - bool m_bEndPortalsEnabled; - /** Name of the nether world */ AString m_NetherWorldName; -- cgit v1.2.3 From 6ab9afd0fd808fad99cd8387c72ce461c37aef80 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 20 Jul 2014 10:46:45 +0100 Subject: Bug and crash fixes * Fixes end portals' solidity * Fixed crashes to do with multithreading and removing an entity from the wrong world * Fixed crashes due to bad merge * Fixed crashes due to an object being deleted twice * Simplified cWorld::Start() and added comments to configuration files --- src/BlockInfo.cpp | 1 + src/Chunk.cpp | 5 ++--- src/ClientHandle.cpp | 2 ++ src/Entities/Entity.cpp | 48 ++++++++++++++++++++++++++++++------------------ src/Entities/Entity.h | 15 +++++++++------ src/Entities/Player.cpp | 35 +++++++++++++++++------------------ src/Entities/Player.h | 15 +++++++++------ src/MobSpawner.cpp | 3 ++- src/Root.cpp | 9 +++++++-- src/Root.h | 13 +++++++++++-- src/World.cpp | 24 ++++++++++++++++-------- src/World.h | 2 +- 12 files changed, 107 insertions(+), 65 deletions(-) diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp index 97e89359f..0882d2740 100644 --- a/src/BlockInfo.cpp +++ b/src/BlockInfo.cpp @@ -496,6 +496,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info) a_Info[E_BLOCK_CROPS ].m_IsSolid = false; a_Info[E_BLOCK_DANDELION ].m_IsSolid = false; a_Info[E_BLOCK_DETECTOR_RAIL ].m_IsSolid = false; + a_Info[E_BLOCK_END_PORTAL ].m_IsSolid = false; a_Info[E_BLOCK_FIRE ].m_IsSolid = false; a_Info[E_BLOCK_FLOWER ].m_IsSolid = false; a_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_IsSolid = false; diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 2f3bdff81..4588de9f3 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -591,7 +591,6 @@ void cChunk::Tick(float a_Dt) if (!((*itr)->IsMob())) { (*itr)->Tick(a_Dt, *this); - continue; } } // for itr - m_Entitites[] @@ -605,10 +604,10 @@ void cChunk::Tick(float a_Dt) itr = m_Entities.erase(itr); delete ToDelete; } - else if ((*itr)->IsTravellingThroughPortal()) // Remove all entities that are travelling to another world + else if ((*itr)->IsWorldTravellingFrom(m_World)) // Remove all entities that are travelling to another world { MarkDirty(); - (*itr)->SetIsTravellingThroughPortal(false); + (*itr)->SetWorldTravellingFrom(NULL); itr = m_Entities.erase(itr); } else if ( // If any entity moved out of the chunk, move it to the neighbor: diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index f90da94dd..8caaae917 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -120,6 +120,8 @@ cClientHandle::~cClientHandle() } if (World != NULL) { + m_Player->SetWorldTravellingFrom(NULL); // Make sure that the player entity is actually removed + World->RemovePlayer(m_Player); // Must be called before cPlayer::Destroy() as otherwise cChunk tries to delete the player, and then we do it again m_Player->Destroy(); } delete m_Player; diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index bd1839580..4768d38ae 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -37,7 +37,7 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d , m_Gravity(-9.81f) , m_LastPos(a_X, a_Y, a_Z) , m_IsInitialized(false) - , m_IsTravellingThroughPortal(false) + , m_WorldTravellingFrom(NULL) , m_EntityType(a_EntityType) , m_World(NULL) , m_IsFireproof(false) @@ -1028,10 +1028,11 @@ void cEntity::DetectCacti(void) void cEntity::DetectPortal() { - if (!GetWorld()->GetNetherWorldName().empty() && !GetWorld()->GetEndWorldName().empty()) + if (GetWorld()->GetDimension() == dimOverworld) { - return; + if (GetWorld()->GetNetherWorldName().empty() && GetWorld()->GetEndWorldName().empty()) { return; } } + else if (GetWorld()->GetLinkedOverworldName().empty()) { return; } int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT; if ((Y > 0) && (Y < cChunkDef::Height)) @@ -1040,7 +1041,7 @@ void cEntity::DetectPortal() { case E_BLOCK_NETHER_PORTAL: { - if (GetWorld()->GetNetherWorldName().empty() || m_PortalCooldownData.second) + if (m_PortalCooldownData.second) { return; } @@ -1054,8 +1055,13 @@ void cEntity::DetectPortal() switch (GetWorld()->GetDimension()) { - case dimNether: + case dimNether: { + if (GetWorld()->GetLinkedOverworldName().empty()) + { + return; + } + m_PortalCooldownData.second = true; // Stop portals from working on respawn if (IsPlayer()) @@ -1068,6 +1074,11 @@ void cEntity::DetectPortal() } case dimOverworld: { + if (GetWorld()->GetNetherWorldName().empty()) + { + return; + } + m_PortalCooldownData.second = true; // Stop portals from working on respawn if (IsPlayer()) @@ -1079,28 +1090,25 @@ void cEntity::DetectPortal() return; } - default: break; + default: return; } - return; } case E_BLOCK_END_PORTAL: { - if (GetWorld()->GetNetherWorldName().empty() || m_PortalCooldownData.second) - { - return; - } - - if (m_PortalCooldownData.first != 80) + if (m_PortalCooldownData.second) { - m_PortalCooldownData.first++; return; } - m_PortalCooldownData.first = 0; switch (GetWorld()->GetDimension()) { case dimEnd: { + if (GetWorld()->GetLinkedOverworldName().empty()) + { + return; + } + m_PortalCooldownData.second = true; // Stop portals from working on respawn if (IsPlayer()) @@ -1115,6 +1123,11 @@ void cEntity::DetectPortal() } case dimOverworld: { + if (GetWorld()->GetEndWorldName().empty()) + { + return; + } + m_PortalCooldownData.second = true; // Stop portals from working on respawn if (IsPlayer()) @@ -1126,9 +1139,8 @@ void cEntity::DetectPortal() return; } - default: break; + default: return; } - return; } default: break; } @@ -1169,7 +1181,7 @@ bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World, bool a_ } // Remove all links to the old world - SetIsTravellingThroughPortal(true); // cChunk handles entity removal + SetWorldTravellingFrom(GetWorld()); // cChunk handles entity removal GetWorld()->BroadcastDestroyEntity(*this); // Queue add to new world diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 8b6fc05f7..eea48a12f 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -387,11 +387,11 @@ public: // tolua_end - /** Returns if the entity is travelling through a portal. Set to true by MoveToWorld and to false when the entity is removed by the old chunk */ - bool IsTravellingThroughPortal(void) const { return m_IsTravellingThroughPortal; } + /** Returns if the entity is travelling away from a specified world */ + bool IsWorldTravellingFrom(cWorld * a_World) const { return (m_WorldTravellingFrom == a_World); } - /** Sets if the entity has begun travelling through a portal or not */ - void SetIsTravellingThroughPortal(bool a_Flag) { m_IsTravellingThroughPortal = a_Flag; } + /** Sets the world the entity will be leaving */ + void SetWorldTravellingFrom(cWorld * a_World) { (m_WorldTravellingFrom = a_World); } /// Updates clients of changes in the entity. virtual void BroadcastMovementUpdate(const cClientHandle * a_Exclude = NULL); @@ -491,8 +491,11 @@ protected: /** True when entity is initialised (Initialize()) and false when destroyed pending deletion (Destroy()) */ bool m_IsInitialized; - /** True when entity is being moved across worlds, false anytime else */ - bool m_IsTravellingThroughPortal; + /** World entity is travelling from + Set by MoveToWorld and back to NULL when the entity is removed by the old chunk + Can't be a simple boolean as context switches between worlds may leave the new chunk processing (and therefore immediately removing) the entity before the old chunk could remove it + */ + cWorld * m_WorldTravellingFrom; eEntityType m_EntityType; diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 2a91600e7..0b1b4ce5f 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -88,7 +88,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) : m_PlayerName = a_PlayerName; - cWorld * World; + cWorld * World = NULL; if (!LoadFromDisk(World)) { m_Inventory.Clear(); @@ -136,8 +136,6 @@ cPlayer::~cPlayer(void) SaveToDisk(); - m_World->RemovePlayer(this); - m_ClientHandle = NULL; delete m_InventoryWindow; @@ -979,7 +977,7 @@ void cPlayer::Respawn(void) m_LifetimeTotalXp = 0; // ToDo: send score to client? How? - m_ClientHandle->SendRespawn(GetWorld()->GetDimension()); + m_ClientHandle->SendRespawn(GetWorld()->GetDimension(), true); // Extinguish the fire: StopBurning(); @@ -1643,11 +1641,12 @@ bool cPlayer::MoveToWorld(const AString & a_WorldName, cWorld * a_World, bool a_ } // Remove player from the old world - SetIsTravellingThroughPortal(true); // cChunk handles entity removal - m_World->RemovePlayer(this); + SetWorldTravellingFrom(GetWorld()); // cChunk handles entity removal + GetWorld()->RemovePlayer(this); // Queue adding player to the new world, including all the necessary adjustments to the object World->AddPlayer(this); + SetWorld(World); return true; } @@ -1697,12 +1696,6 @@ void cPlayer::LoadPermissionsFromDisk() bool cPlayer::LoadFromDisk(cWorldPtr & a_World) { - a_World = cRoot::Get()->GetWorld(GetLoadedWorldName()); - if (a_World == NULL) - { - a_World = cRoot::Get()->GetDefaultWorld(); - } - LoadPermissionsFromDisk(); // Load from the UUID file: @@ -1740,6 +1733,11 @@ bool cPlayer::LoadFromDisk(cWorldPtr & a_World) LOG("Player data file not found for %s (%s, offline %s), will be reset to defaults.", GetName().c_str(), m_UUID.c_str(), OfflineUUID.c_str() ); + + if (a_World == NULL) + { + a_World = cRoot::Get()->GetDefaultWorld(); + } return false; } @@ -1747,7 +1745,7 @@ bool cPlayer::LoadFromDisk(cWorldPtr & a_World) -bool cPlayer::LoadFromFile(const AString & a_FileName, cWorld * a_World) +bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World) { // Load the data from the file: cFile f; @@ -1800,9 +1798,6 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorld * a_World) m_LifetimeTotalXp = (short) root.get("xpTotal", 0).asInt(); m_CurrentXp = (short) root.get("xpCurrent", 0).asInt(); m_IsFlying = root.get("isflying", 0).asBool(); - m_LastBedPos.x = root.get("SpawnX", a_World->GetSpawnX()).asInt(); - m_LastBedPos.y = root.get("SpawnY", a_World->GetSpawnY()).asInt(); - m_LastBedPos.z = root.get("SpawnZ", a_World->GetSpawnZ()).asInt(); m_GameMode = (eGameMode) root.get("gamemode", eGameMode_NotSet).asInt(); @@ -1815,6 +1810,11 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorld * a_World) cEnderChestEntity::LoadFromJson(root["enderchestinventory"], m_EnderChestContents); m_LoadedWorldName = root.get("world", "world").asString(); + a_World = cRoot::Get()->GetWorld(GetLoadedWorldName(), true); + + m_LastBedPos.x = root.get("SpawnX", a_World->GetSpawnX()).asInt(); + m_LastBedPos.y = root.get("SpawnY", a_World->GetSpawnY()).asInt(); + m_LastBedPos.z = root.get("SpawnZ", a_World->GetSpawnZ()).asInt(); // Load the player stats. // We use the default world name (like bukkit) because stats are shared between dimensions/worlds. @@ -1822,7 +1822,7 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorld * a_World) StatSerializer.Load(); LOGD("Player %s was read from file \"%s\", spawning at {%.2f, %.2f, %.2f} in world \"%s\"", - GetName().c_str(), a_FileName.c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str() + GetName().c_str(), a_FileName.c_str(), GetPosX(), GetPosY(), GetPosZ(), a_World->GetName().c_str() ); return true; @@ -1834,7 +1834,6 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorld * a_World) bool cPlayer::SaveToDisk() { - cFile::CreateFolder(FILE_IO_PREFIX + AString("players")); cFile::CreateFolder(FILE_IO_PREFIX + AString("players/") + m_UUID.substr(0, 2)); // create the JSON data diff --git a/src/Entities/Player.h b/src/Entities/Player.h index ad434f036..226ec5e68 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -340,14 +340,17 @@ public: typedef cWorld * cWorldPtr; - /** Loads the player data from the disk file. -Takes a (NULL) cWorld pointer which it will assign a value to based on either the loaded world or default world - Returns true on success, false on failure. */ + /** Loads the player data from the disk file + Takes a (NULL) cWorld pointer which it will assign a value to based on either the loaded world or default world by calling LoadFromFile() + Returns true on success, false on failure + */ bool LoadFromDisk(cWorldPtr & a_World); - /** Loads the player data from the specified file. - Returns true on success, false on failure. */ - bool LoadFromFile(const AString & a_FileName, cWorld * a_World); + /** Loads the player data from the specified file + Takes a (NULL) cWorld pointer which it will assign a value to based on either the loaded world or default world + Returns true on success, false on failure + */ + bool LoadFromFile(const AString & a_FileName, cWorldPtr & a_World); void LoadPermissionsFromDisk(void); // tolua_export diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp index da3e7c406..d09bbc943 100644 --- a/src/MobSpawner.cpp +++ b/src/MobSpawner.cpp @@ -241,7 +241,8 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R (m_Random.NextInt(2, a_Biome) == 0) ); } - + + case cMonster::mtMagmaCube: case cMonster::mtSlime: { return ( diff --git a/src/Root.cpp b/src/Root.cpp index 822be92ff..e1eebb711 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -322,7 +322,7 @@ cWorld * cRoot::CreateAndInitializeWorld(const AString & a_WorldName, eDimension } cWorld * NewWorld = new cWorld(a_WorldName.c_str(), a_Dimension, a_OverworldName); m_WorldsByName[a_WorldName] = NewWorld; - NewWorld->Start(!a_OverworldName.empty()); + NewWorld->Start(); NewWorld->InitializeSpawn(); m_PluginManager->CallHookWorldStarted(*NewWorld); return NewWorld; @@ -381,13 +381,18 @@ cWorld * cRoot::GetDefaultWorld() -cWorld * cRoot::GetWorld(const AString & a_WorldName) +cWorld * cRoot::GetWorld(const AString & a_WorldName, bool a_SearchForFolder) { WorldMap::iterator itr = m_WorldsByName.find(a_WorldName); if (itr != m_WorldsByName.end()) { return itr->second; } + + if (a_SearchForFolder && cFile::IsFolder(FILE_IO_PREFIX + a_WorldName)) + { + return CreateAndInitializeWorld(a_WorldName); + } return NULL; } diff --git a/src/Root.h b/src/Root.h index c3aca37f9..4e3fcf080 100644 --- a/src/Root.h +++ b/src/Root.h @@ -51,8 +51,17 @@ public: // tolua_begin cServer * GetServer(void) { return m_Server; } cWorld * GetDefaultWorld(void); - cWorld * GetWorld(const AString & a_WorldName); - cWorld * CreateAndInitializeWorld(const AString & a_WorldName, eDimension a_Dimension = dimOverworld, const AString & a_OverworldName = ""); + + /** Returns a pointer to the world specified + If no world of that name was currently loaded and a_SearchForFolder was true, it will consult cFile::IsFolder() to see if a world folder of that name exists and if so, initialise a world based on that name + */ + cWorld * GetWorld(const AString & a_WorldName, bool a_SearchForFolder = false); + + /** Returns a pointer to a world of specified name - will search loaded worlds first, then create anew if not found + The dimension parameter is used to create a world with a specific dimension + a_OverworldName should be set for non-overworld dimensions if one wishes that world to link back to an overworld via portals + */ + cWorld * CreateAndInitializeWorld(const AString & a_WorldName, eDimension a_Dimension = dimOverworld, const AString & a_OverworldName = ""); // tolua_end /// Calls the callback for each world; returns true if the callback didn't abort (return true) diff --git a/src/World.cpp b/src/World.cpp index 924d5adbb..d27ad1eb4 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -512,7 +512,7 @@ void cWorld::InitializeSpawn(void) -void cWorld::Start(bool a_WasDimensionSet) +void cWorld::Start() { m_SpawnX = 0; m_SpawnY = cChunkDef::Height; @@ -523,11 +523,15 @@ void cWorld::Start(bool a_WasDimensionSet) if (!IniFile.ReadFile(m_IniFileName)) { LOGWARNING("Cannot read world settings from \"%s\", defaults will be used.", m_IniFileName.c_str()); + + // TODO: More descriptions for each key + IniFile.AddHeaderComment(" This is the per-world configuration file, managing settings such as generators, simulators, and spawn points"); + IniFile.AddKeyComment("LinkedWorlds", "This section governs portal world linkage; leave a value blank to disabled that associated method of teleportation"); } - AString Dimension = IniFile.GetValueSet("General", "Dimension", a_WasDimensionSet ? DimensionToString(GetDimension()) : "Overworld"); - m_Dimension = StringToDimension(Dimension); - m_OverworldName = IniFile.GetValue("LinkedWorlds", "OverworldName", a_WasDimensionSet ? m_OverworldName : ""); + // The presence of a configuration value overrides everything + // If no configuration value is found, GetDimension() is written to file and the variable is written to again to ensure that cosmic rays haven't sneakily changed its value + m_Dimension = StringToDimension(IniFile.GetValueSet("General", "Dimension", DimensionToString(GetDimension()))); // Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found int KeyNum = IniFile.FindKey("SpawnPosition"); @@ -535,8 +539,8 @@ void cWorld::Start(bool a_WasDimensionSet) ( (KeyNum >= 0) && ( - (IniFile.FindValue(KeyNum, "X") >= 0) || - (IniFile.FindValue(KeyNum, "Y") >= 0) || + (IniFile.FindValue(KeyNum, "X") >= 0) && + (IniFile.FindValue(KeyNum, "Y") >= 0) && (IniFile.FindValue(KeyNum, "Z") >= 0) ) ); @@ -575,11 +579,15 @@ void cWorld::Start(bool a_WasDimensionSet) int Weather = IniFile.GetValueSetI("General", "Weather", (int)m_Weather); m_TimeOfDay = IniFile.GetValueSetI("General", "TimeInTicks", m_TimeOfDay); - if ((GetDimension() != dimNether) && (GetDimension() != dimEnd)) + if (GetDimension() == dimOverworld) { m_NetherWorldName = IniFile.GetValueSet("LinkedWorlds", "NetherWorldName", DEFAULT_NETHER_NAME); m_EndWorldName = IniFile.GetValueSet("LinkedWorlds", "EndWorldName", DEFAULT_END_NAME); } + else + { + m_OverworldName = IniFile.GetValueSet("LinkedWorlds", "OverworldName", GetLinkedOverworldName()); + } // Adjust the enum-backed variables into their respective bounds: m_GameMode = (eGameMode) Clamp(GameMode, (int)gmSurvival, (int)gmAdventure); @@ -2420,7 +2428,7 @@ void cWorld::AddPlayer(cPlayer * a_Player) void cWorld::RemovePlayer(cPlayer * a_Player) { - if (!a_Player->IsTravellingThroughPortal()) + if (!a_Player->IsWorldTravellingFrom(this)) { m_ChunkMap->RemoveEntity(a_Player); } diff --git a/src/World.h b/src/World.h index 73b8b81b0..09cbc6b48 100644 --- a/src/World.h +++ b/src/World.h @@ -669,7 +669,7 @@ public: void InitializeSpawn(void); /** Starts threads that belong to this world */ - void Start(bool a_WasDimensionSet = true); + void Start(); /** Stops threads that belong to this world (part of deinit) */ void Stop(void); -- cgit v1.2.3 From 8050a5b98a3003c2a4bed39b896b4a3a4c1068c0 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Mon, 21 Jul 2014 22:49:06 +0100 Subject: Suggestions --- lib/inifile/iniFile.cpp | 2 +- src/BlockID.h | 2 +- src/Chunk.cpp | 6 +-- src/ChunkMap.cpp | 1 - src/Entities/Entity.cpp | 78 +++++++++++++++------------- src/Entities/Entity.h | 30 +++++++---- src/Entities/Player.cpp | 25 ++------- src/Entities/Player.h | 2 +- src/World.cpp | 135 ++++++++++++++++++++++++++++-------------------- src/World.h | 7 +++ 10 files changed, 161 insertions(+), 127 deletions(-) diff --git a/lib/inifile/iniFile.cpp b/lib/inifile/iniFile.cpp index 30f93e5a3..2bf6c91ed 100644 --- a/lib/inifile/iniFile.cpp +++ b/lib/inifile/iniFile.cpp @@ -585,7 +585,7 @@ Int64 cIniFile::GetValueSetI(const AString & keyname, const AString & valuename, AString Data; Printf(Data, "%lld", defValue); AString resultstring = GetValueSet(keyname, valuename, Data); - Int64 result; + Int64 result = defValue; #ifdef _WIN32 sscanf_s(resultstring.c_str(), "%lld", &result); #else diff --git a/src/BlockID.h b/src/BlockID.h index 37eed8eda..08c576886 100644 --- a/src/BlockID.h +++ b/src/BlockID.h @@ -924,7 +924,7 @@ extern int StringToMobType(const AString & a_MobString); extern eDimension StringToDimension(const AString & a_DimensionString); /** Translates a dimension enum to dimension string. -Takes a string and returns "Overworld" on failure +Takes an eDimension enum value and returns "Overworld" on failure */ extern AString DimensionToString(eDimension a_Dimension); diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 4588de9f3..7850b7e31 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -596,7 +596,7 @@ void cChunk::Tick(float a_Dt) for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) { - if ((*itr)->IsDestroyed()) // Remove all entities that were scheduled for removal: + if ((*itr)->IsDestroyed()) // Remove all entities that were scheduled for removal: { LOGD("Destroying entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass()); MarkDirty(); @@ -604,13 +604,13 @@ void cChunk::Tick(float a_Dt) itr = m_Entities.erase(itr); delete ToDelete; } - else if ((*itr)->IsWorldTravellingFrom(m_World)) // Remove all entities that are travelling to another world + else if ((*itr)->IsWorldTravellingFrom(m_World)) // Remove all entities that are travelling to another world { MarkDirty(); (*itr)->SetWorldTravellingFrom(NULL); itr = m_Entities.erase(itr); } - else if ( // If any entity moved out of the chunk, move it to the neighbor: + else if ( // If any entity moved out of the chunk, move it to the neighbor: ((*itr)->GetChunkX() != m_PosX) || ((*itr)->GetChunkZ() != m_PosZ) ) diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 3cfa5c3f5..e91f77d27 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -2427,7 +2427,6 @@ bool cChunkMap::ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinCh { for (int x = a_MinChunkX; x <= a_MaxChunkX; x++) { - LOG("Request %i %i", x, z); cChunkPtr Chunk = GetChunkNoLoad(x, ZERO_CHUNK_Y, z); if ((Chunk == NULL) || (!Chunk->IsValid())) { diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 4768d38ae..1254541ed 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1030,9 +1030,15 @@ void cEntity::DetectPortal() { if (GetWorld()->GetDimension() == dimOverworld) { - if (GetWorld()->GetNetherWorldName().empty() && GetWorld()->GetEndWorldName().empty()) { return; } + if (GetWorld()->GetNetherWorldName().empty() && GetWorld()->GetEndWorldName().empty()) + { + return; + } + } + else if (GetWorld()->GetLinkedOverworldName().empty()) + { + return; } - else if (GetWorld()->GetLinkedOverworldName().empty()) { return; } int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT; if ((Y > 0) && (Y < cChunkDef::Height)) @@ -1041,17 +1047,17 @@ void cEntity::DetectPortal() { case E_BLOCK_NETHER_PORTAL: { - if (m_PortalCooldownData.second) + if (m_PortalCooldownData.m_ShouldPreventTeleportation) { return; } - if (m_PortalCooldownData.first != 80) + if (IsPlayer() && !((cPlayer *)this)->IsGameModeCreative() && m_PortalCooldownData.m_TicksDelayed != 80) { - m_PortalCooldownData.first++; + m_PortalCooldownData.m_TicksDelayed++; return; } - m_PortalCooldownData.first = 0; + m_PortalCooldownData.m_TicksDelayed = 0; switch (GetWorld()->GetDimension()) { @@ -1062,13 +1068,13 @@ void cEntity::DetectPortal() return; } - m_PortalCooldownData.second = true; // Stop portals from working on respawn + m_PortalCooldownData.m_ShouldPreventTeleportation = true; // Stop portals from working on respawn if (IsPlayer()) { ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimOverworld); } - MoveToWorld(GetWorld()->GetLinkedOverworldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false); + MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false); return; } @@ -1079,14 +1085,14 @@ void cEntity::DetectPortal() return; } - m_PortalCooldownData.second = true; // Stop portals from working on respawn + m_PortalCooldownData.m_ShouldPreventTeleportation = true; // Stop portals from working on respawn if (IsPlayer()) { ((cPlayer *)this)->AwardAchievement(achEnterPortal); ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimNether); } - MoveToWorld(GetWorld()->GetNetherWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName(), dimNether, GetWorld()->GetName()), false); + MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName(), dimNether, GetWorld()->GetName()), false); return; } @@ -1095,7 +1101,7 @@ void cEntity::DetectPortal() } case E_BLOCK_END_PORTAL: { - if (m_PortalCooldownData.second) + if (m_PortalCooldownData.m_ShouldPreventTeleportation) { return; } @@ -1109,7 +1115,7 @@ void cEntity::DetectPortal() return; } - m_PortalCooldownData.second = true; // Stop portals from working on respawn + m_PortalCooldownData.m_ShouldPreventTeleportation = true; // Stop portals from working on respawn if (IsPlayer()) { @@ -1117,7 +1123,7 @@ void cEntity::DetectPortal() Player->TeleportToCoords(Player->GetLastBedPos().x, Player->GetLastBedPos().y, Player->GetLastBedPos().z); Player->GetClientHandle()->SendRespawn(dimOverworld); } - MoveToWorld(GetWorld()->GetLinkedOverworldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false); + MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false); return; } @@ -1128,14 +1134,14 @@ void cEntity::DetectPortal() return; } - m_PortalCooldownData.second = true; // Stop portals from working on respawn + m_PortalCooldownData.m_ShouldPreventTeleportation = true; // Stop portals from working on respawn if (IsPlayer()) { ((cPlayer *)this)->AwardAchievement(achEnterTheEnd); ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimEnd); } - MoveToWorld(GetWorld()->GetEndWorldName(), cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName(), dimEnd, GetWorld()->GetName()), false); + MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName(), dimEnd, GetWorld()->GetName()), false); return; } @@ -1147,34 +1153,20 @@ void cEntity::DetectPortal() } // Allow portals to work again - m_PortalCooldownData.second = false; - m_PortalCooldownData.first = 0; + m_PortalCooldownData.m_ShouldPreventTeleportation = false; + m_PortalCooldownData.m_ShouldPreventTeleportation = 0; } -bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World, bool a_ShouldSendRespawn) +bool cEntity::MoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) { UNUSED(a_ShouldSendRespawn); + ASSERT(a_World == NULL); - cWorld * World; - if (a_World == NULL) - { - World = cRoot::Get()->GetWorld(a_WorldName); - if (World == NULL) - { - LOG("%s: Couldn't find world \"%s\".", __FUNCTION__, a_WorldName.c_str()); - return false; - } - } - else - { - World = a_World; - } - - if (GetWorld() == World) + if (GetWorld() == a_World) { // Don't move to same world return false; @@ -1185,7 +1177,7 @@ bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World, bool a_ GetWorld()->BroadcastDestroyEntity(*this); // Queue add to new world - World->AddEntity(this); + a_World->AddEntity(this); return true; } @@ -1194,6 +1186,22 @@ bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World, bool a_ +bool cEntity::MoveToWorld(const AString & a_WorldName, bool a_ShouldSendRespawn) +{ + cWorld * World = cRoot::Get()->GetWorld(a_WorldName); + if (World == NULL) + { + LOG("%s: Couldn't find world \"%s\".", __FUNCTION__, a_WorldName.c_str()); + return false; + } + + return MoveToWorld(World, a_ShouldSendRespawn); +} + + + + + void cEntity::SetSwimState(cChunk & a_Chunk) { int RelY = (int)floor(GetPosY() + 0.1); diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index eea48a12f..58254a493 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -382,16 +382,19 @@ public: /// Teleports to the coordinates specified virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ); - /** Moves entity to specified world */ - virtual bool MoveToWorld(const AString & a_WorldName, cWorld * a_World = NULL, bool a_ShouldSendRespawn = true); + /** Moves entity to specified world, taking a world pointer */ + virtual bool MoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn = true); + + /** Moves entity to specified world, taking a world name */ + bool MoveToWorld(const AString & a_WorldName, bool a_ShouldSendRespawn = true); // tolua_end /** Returns if the entity is travelling away from a specified world */ - bool IsWorldTravellingFrom(cWorld * a_World) const { return (m_WorldTravellingFrom == a_World); } + bool IsWorldTravellingFrom(cWorld * a_World) const { return m_WorldTravellingFrom == a_World; } /** Sets the world the entity will be leaving */ - void SetWorldTravellingFrom(cWorld * a_World) { (m_WorldTravellingFrom = a_World); } + void SetWorldTravellingFrom(cWorld * a_World) { m_WorldTravellingFrom = a_World; } /// Updates clients of changes in the entity. virtual void BroadcastMovementUpdate(const cClientHandle * a_Exclude = NULL); @@ -538,11 +541,20 @@ protected: int m_AirLevel; int m_AirTickTimer; - /** Portal delay timer and cooldown boolean - First value is to delay sending the respawn packet (which triggers the Entering the {Dimension} screen). - Second value is to prevent a teleportation loop by ensuring we do not reenter a portal that we came out of. - */ - std::pair m_PortalCooldownData; + /** Structure storing the portal delay timer and cooldown boolean */ + struct sPortalCooldownData + { + /** Ticks since entry of portal, used to delay teleportation */ + unsigned short m_TicksDelayed; + + /** Whether the entity has just exited the portal, and should therefore not be teleported again + This prevents teleportation loops, and is reset when the entity has moved out of the portal + */ + bool m_ShouldPreventTeleportation; + }; + + /** Portal delay timer and cooldown boolean data */ + sPortalCooldownData m_PortalCooldownData; private: /** Measured in degrees, [-180, +180) */ diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 0b1b4ce5f..1159891cd 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1611,24 +1611,9 @@ void cPlayer::TossItems(const cItems & a_Items) -bool cPlayer::MoveToWorld(const AString & a_WorldName, cWorld * a_World, bool a_ShouldSendRespawn) +bool cPlayer::MoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) { - cWorld * World; - if (a_World == NULL) - { - World = cRoot::Get()->GetWorld(a_WorldName); - if (World == NULL) - { - LOG("%s: Couldn't find world \"%s\".", __FUNCTION__, a_WorldName.c_str()); - return false; - } - } - else - { - World = a_World; - } - - if (GetWorld() == World) + if (GetWorld() == a_World) { // Don't move to same world return false; @@ -1637,7 +1622,7 @@ bool cPlayer::MoveToWorld(const AString & a_WorldName, cWorld * a_World, bool a_ // Send the respawn packet: if (a_ShouldSendRespawn && (m_ClientHandle != NULL)) { - m_ClientHandle->SendRespawn(World->GetDimension()); + m_ClientHandle->SendRespawn(a_World->GetDimension()); } // Remove player from the old world @@ -1645,8 +1630,8 @@ bool cPlayer::MoveToWorld(const AString & a_WorldName, cWorld * a_World, bool a_ GetWorld()->RemovePlayer(this); // Queue adding player to the new world, including all the necessary adjustments to the object - World->AddPlayer(this); - SetWorld(World); + a_World->AddPlayer(this); + SetWorld(a_World); // Chunks may be streamed before cWorld::AddPlayer() sets the world to the new value return true; } diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 226ec5e68..f972063bb 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -333,7 +333,7 @@ public: /** Moves the player to the specified world. Returns true if successful, false on failure (world not found). */ - virtual bool MoveToWorld(const AString & a_WorldName, cWorld * a_World = NULL, bool a_ShouldSendRespawn = true) override; // tolua_export + virtual bool MoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn = true) override; // tolua_export /** Saves all player data, such as inventory, to JSON */ bool SaveToDisk(void); diff --git a/src/World.cpp b/src/World.cpp index d27ad1eb4..2af8fc59e 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -512,7 +512,7 @@ void cWorld::InitializeSpawn(void) -void cWorld::Start() +void cWorld::Start(void) { m_SpawnX = 0; m_SpawnY = cChunkDef::Height; @@ -594,61 +594,8 @@ void cWorld::Start() m_TNTShrapnelLevel = (eShrapnelLevel)Clamp(TNTShrapnelLevel, (int)slNone, (int)slAll); m_Weather = (eWeather) Clamp(Weather, (int)wSunny, (int)wStorm); - switch (GetDimension()) - { - case dimEnd: - { - IniFile.GetValueSet("Generator", "BiomeGen", "Constant"); - IniFile.GetValueSet("Generator", "ConstantBiome", "End"); - IniFile.GetValueSet("Generator", "HeightGen", "Biomal"); - IniFile.GetValueSet("Generator", "CompositionGen", "End"); - break; - } - case dimOverworld: - { - IniFile.GetValueSet("Generator", "BiomeGen", "MultiStepMap"); - IniFile.GetValueSet("Generator", "HeightGen", "DistortedHeightmap"); - IniFile.GetValueSet("Generator", "CompositionGen", "DistortedHeightmap"); - IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator"); - break; - } - case dimNether: - { - IniFile.GetValueSet("Generator", "BiomeGen", "Constant"); - IniFile.GetValueSet("Generator", "ConstantBiome", "Nether"); - IniFile.GetValueSet("Generator", "HeightGen", "Flat"); - IniFile.GetValueSet("Generator", "FlatHeight", "128"); - IniFile.GetValueSet("Generator", "CompositionGen", "Nether"); - IniFile.GetValueSet("Generator", "Finishers", "WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherForts, PreSimulator"); - IniFile.GetValueSet("Generator", "BottomLavaHeight", "30"); - break; - } - } - - // Load allowed mobs: - const char * DefaultMonsters = ""; - switch (m_Dimension) - { - case dimOverworld: DefaultMonsters = "bat, cavespider, chicken, cow, creeper, enderman, horse, mooshroom, ocelot, pig, sheep, silverfish, skeleton, slime, spider, squid, wolf, zombie"; break; - case dimNether: DefaultMonsters = "blaze, ghast, magmacube, skeleton, zombie, zombiepigman"; break; - case dimEnd: DefaultMonsters = "enderman"; break; - } - m_bAnimals = IniFile.GetValueSetB("Monsters", "AnimalsOn", true); - AString AllMonsters = IniFile.GetValueSet("Monsters", "Types", DefaultMonsters); - AStringVector SplitList = StringSplitAndTrim(AllMonsters, ","); - for (AStringVector::const_iterator itr = SplitList.begin(), end = SplitList.end(); itr != end; ++itr) - { - cMonster::eType ToAdd = cMonster::StringToMobType(*itr); - if (ToAdd != cMonster::mtInvalidType) - { - m_AllowedMobs.insert(ToAdd); - LOGD("Allowed mob: %s", itr->c_str()); - } - else - { - LOG("World \"%s\": Unknown mob type: %s", m_WorldName.c_str(), itr->c_str()); - } - } + InitialiseGeneratorDefaults(IniFile); + InitialiseAndLoadMobSpawningValues(IniFile); m_ChunkMap = new cChunkMap(this); @@ -745,6 +692,82 @@ eWeather cWorld::ChooseNewWeather() +void cWorld::InitialiseGeneratorDefaults(cIniFile & a_IniFile) +{ + switch (GetDimension()) + { + case dimEnd: + { + a_IniFile.GetValueSet("Generator", "BiomeGen", "Constant"); + a_IniFile.GetValueSet("Generator", "ConstantBiome", "End"); + a_IniFile.GetValueSet("Generator", "HeightGen", "Biomal"); + a_IniFile.GetValueSet("Generator", "CompositionGen", "End"); + break; + } + case dimOverworld: + { + a_IniFile.GetValueSet("Generator", "BiomeGen", "MultiStepMap"); + a_IniFile.GetValueSet("Generator", "HeightGen", "DistortedHeightmap"); + a_IniFile.GetValueSet("Generator", "CompositionGen", "DistortedHeightmap"); + a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator"); + break; + } + case dimNether: + { + a_IniFile.GetValueSet("Generator", "BiomeGen", "Constant"); + a_IniFile.GetValueSet("Generator", "ConstantBiome", "Nether"); + a_IniFile.GetValueSet("Generator", "HeightGen", "Flat"); + a_IniFile.GetValueSet("Generator", "FlatHeight", "128"); + a_IniFile.GetValueSet("Generator", "CompositionGen", "Nether"); + a_IniFile.GetValueSet("Generator", "Finishers", "WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherForts, PreSimulator"); + a_IniFile.GetValueSet("Generator", "BottomLavaHeight", "30"); + break; + } + } +} + + + + + +void cWorld::InitialiseAndLoadMobSpawningValues(cIniFile & a_IniFile) +{ + AString DefaultMonsters; + switch (m_Dimension) + { + case dimOverworld: DefaultMonsters = "bat, cavespider, chicken, cow, creeper, enderman, horse, mooshroom, ocelot, pig, sheep, silverfish, skeleton, slime, spider, squid, wolf, zombie"; break; + case dimNether: DefaultMonsters = "blaze, ghast, magmacube, skeleton, zombie, zombiepigman"; break; + case dimEnd: DefaultMonsters = "enderman"; break; + } + + m_bAnimals = a_IniFile.GetValueSetB("Monsters", "AnimalsOn", true); + AString AllMonsters = a_IniFile.GetValueSet("Monsters", "Types", DefaultMonsters); + + if (!m_bAnimals) + { + return; + } + + AStringVector SplitList = StringSplitAndTrim(AllMonsters, ","); + for (AStringVector::const_iterator itr = SplitList.begin(), end = SplitList.end(); itr != end; ++itr) + { + cMonster::eType ToAdd = cMonster::StringToMobType(*itr); + if (ToAdd != cMonster::mtInvalidType) + { + m_AllowedMobs.insert(ToAdd); + LOGD("Allowed mob: %s", itr->c_str()); + } + else + { + LOG("World \"%s\": Unknown mob type: %s", m_WorldName.c_str(), itr->c_str()); + } + } +} + + + + + void cWorld::Stop(void) { // Delete the clients that have been in this world: diff --git a/src/World.h b/src/World.h index 09cbc6b48..879da3cb9 100644 --- a/src/World.h +++ b/src/World.h @@ -1030,6 +1030,13 @@ private: /** Adds the players queued in the m_PlayersToAdd queue into the m_Players list. Assumes it is called from the Tick thread. */ void AddQueuedPlayers(void); + + /** Sets generator values to dimension specific defaults, if those values do not exist */ + void InitialiseGeneratorDefaults(cIniFile & a_IniFile); + + /** Sets mob spawning values if nonexistant to their dimension specific defaults */ + void InitialiseAndLoadMobSpawningValues(cIniFile & a_IniFile); + }; // tolua_export -- cgit v1.2.3 From 0a15e1f420402e797397ea447b1df96f6ea2106f Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Tue, 22 Jul 2014 10:33:16 +0100 Subject: Suggestion and failed merge fix --- src/Blocks/BlockPortal.h | 2 +- src/World.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h index 6f41f96df..fc74e89d0 100644 --- a/src/Blocks/BlockPortal.h +++ b/src/Blocks/BlockPortal.h @@ -55,7 +55,7 @@ public: virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - if ((a_RelY == 0) || (a_RelY == cChunkDef::Height)) // Y can't be < 0 or > Height; (Fast)SetBlock won't allow it + if ((a_RelY - 1 < 0) || (a_RelY + 1 > cChunkDef::Height)) { return false; // In case someone places a portal with meta 1 or 2 at boundaries, and server tries to get invalid coords at Y - 1 or Y + 1 } diff --git a/src/World.cpp b/src/World.cpp index 9dc28afea..2736e77d3 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -579,6 +579,11 @@ void cWorld::Start(void) int Weather = IniFile.GetValueSetI("General", "Weather", (int)m_Weather); m_TimeOfDay = IniFile.GetValueSetI("General", "TimeInTicks", m_TimeOfDay); + if (GetDimension() == dimOverworld) + { + m_NetherWorldName = IniFile.GetValueSet("LinkedWorlds", "NetherWorldName", DEFAULT_NETHER_NAME); + m_EndWorldName = IniFile.GetValueSet("LinkedWorlds", "EndWorldName", DEFAULT_END_NAME); + } else { m_OverworldName = IniFile.GetValueSet("LinkedWorlds", "OverworldName", GetLinkedOverworldName()); -- cgit v1.2.3 From a28b0dc1201dca7c34d9a6c33232157e45a6d4f8 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Tue, 22 Jul 2014 17:26:48 +0100 Subject: Speed improvements, crash fixes, & self-suggestions --- src/Chunk.cpp | 19 ++++++---------- src/Entities/Entity.cpp | 59 ++++++++++++++++++++++++------------------------- src/Entities/Entity.h | 6 +++-- src/Entities/Player.cpp | 6 +++-- src/Entities/Player.h | 1 - src/Root.cpp | 6 +++-- src/World.cpp | 17 +++++--------- src/World.h | 2 +- 8 files changed, 55 insertions(+), 61 deletions(-) diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 9b9646b0c..0be61f753 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -583,19 +583,14 @@ void cChunk::Tick(float a_Dt) m_IsDirty = (*itr)->Tick(a_Dt, *this) | m_IsDirty; } - // Tick all entities in this chunk (except mobs): - for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) - { - // Mobs are ticked inside cWorld::TickMobs() (as we don't have to tick them if they are far away from players) - // Don't tick things queued to be removed - if (!((*itr)->IsMob())) + for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) + { + if (!((*itr)->IsMob())) // Mobs are ticked inside cWorld::TickMobs() (as we don't have to tick them if they are far away from players) { + // Tick all entities in this chunk (except mobs): (*itr)->Tick(a_Dt, *this); } - } // for itr - m_Entitites[] - - for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) - { + if ((*itr)->IsDestroyed()) // Remove all entities that were scheduled for removal: { LOGD("Destroying entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass()); @@ -604,7 +599,7 @@ void cChunk::Tick(float a_Dt) itr = m_Entities.erase(itr); delete ToDelete; } - else if ((*itr)->IsWorldTravellingFrom(m_World)) // Remove all entities that are travelling to another world + else if ((*itr)->IsWorldTravellingFrom(m_World)) // Remove all entities that are travelling to another world: { MarkDirty(); (*itr)->SetWorldTravellingFrom(NULL); @@ -1899,7 +1894,7 @@ void cChunk::AddEntity(cEntity * a_Entity) MarkDirty(); } - ASSERT(std::find(m_Entities.begin(), m_Entities.end(), a_Entity) == m_Entities.end()); + ASSERT(std::find(m_Entities.begin(), m_Entities.end(), a_Entity) == m_Entities.end()); // Not there already m_Entities.push_back(a_Entity); } diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index a7340a29c..68bfabb30 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -614,11 +614,13 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk) // Handle drowning HandleAir(); + } + + if (!DetectPortal()) // Our chunk is invalid if we have moved to another world + { + // None of the above functions changed position, we remain in the chunk of NextChunk + HandlePhysics(a_Dt, *NextChunk); } - DetectPortal(); - - // None of the above functions change position, we remain in the chunk of NextChunk - HandlePhysics(a_Dt, *NextChunk); } } @@ -1026,18 +1028,18 @@ void cEntity::DetectCacti(void) -void cEntity::DetectPortal() +bool cEntity::DetectPortal() { if (GetWorld()->GetDimension() == dimOverworld) { if (GetWorld()->GetNetherWorldName().empty() && GetWorld()->GetEndWorldName().empty()) { - return; + return false; } } else if (GetWorld()->GetLinkedOverworldName().empty()) { - return; + return false; } int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT; @@ -1049,13 +1051,13 @@ void cEntity::DetectPortal() { if (m_PortalCooldownData.m_ShouldPreventTeleportation) { - return; + return false; } if (IsPlayer() && !((cPlayer *)this)->IsGameModeCreative() && m_PortalCooldownData.m_TicksDelayed != 80) { m_PortalCooldownData.m_TicksDelayed++; - return; + return false; } m_PortalCooldownData.m_TicksDelayed = 0; @@ -1065,7 +1067,7 @@ void cEntity::DetectPortal() { if (GetWorld()->GetLinkedOverworldName().empty()) { - return; + return false; } m_PortalCooldownData.m_ShouldPreventTeleportation = true; // Stop portals from working on respawn @@ -1074,15 +1076,14 @@ void cEntity::DetectPortal() { ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimOverworld); } - MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false); - - return; + + return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false); } case dimOverworld: { if (GetWorld()->GetNetherWorldName().empty()) { - return; + return false; } m_PortalCooldownData.m_ShouldPreventTeleportation = true; // Stop portals from working on respawn @@ -1092,18 +1093,17 @@ void cEntity::DetectPortal() ((cPlayer *)this)->AwardAchievement(achEnterPortal); ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimNether); } - MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName(), dimNether, GetWorld()->GetName()), false); - - return; + + return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName(), dimNether, GetWorld()->GetName()), false); } - default: return; + default: return false; } } case E_BLOCK_END_PORTAL: { if (m_PortalCooldownData.m_ShouldPreventTeleportation) { - return; + return false; } switch (GetWorld()->GetDimension()) @@ -1112,7 +1112,7 @@ void cEntity::DetectPortal() { if (GetWorld()->GetLinkedOverworldName().empty()) { - return; + return false; } m_PortalCooldownData.m_ShouldPreventTeleportation = true; // Stop portals from working on respawn @@ -1122,16 +1122,15 @@ void cEntity::DetectPortal() cPlayer * Player = (cPlayer *)this; Player->TeleportToCoords(Player->GetLastBedPos().x, Player->GetLastBedPos().y, Player->GetLastBedPos().z); Player->GetClientHandle()->SendRespawn(dimOverworld); - } - MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false); + } - return; + return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false); } case dimOverworld: { if (GetWorld()->GetEndWorldName().empty()) { - return; + return false; } m_PortalCooldownData.m_ShouldPreventTeleportation = true; // Stop portals from working on respawn @@ -1140,12 +1139,11 @@ void cEntity::DetectPortal() { ((cPlayer *)this)->AwardAchievement(achEnterTheEnd); ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimEnd); - } - MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName(), dimEnd, GetWorld()->GetName()), false); + } - return; + return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName(), dimEnd, GetWorld()->GetName()), false); } - default: return; + default: return false; } } default: break; @@ -1155,6 +1153,7 @@ void cEntity::DetectPortal() // Allow portals to work again m_PortalCooldownData.m_ShouldPreventTeleportation = false; m_PortalCooldownData.m_ShouldPreventTeleportation = 0; + return false; } @@ -1164,7 +1163,7 @@ void cEntity::DetectPortal() bool cEntity::MoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) { UNUSED(a_ShouldSendRespawn); - ASSERT(a_World == NULL); + ASSERT(a_World != NULL); if (GetWorld() == a_World) { @@ -1173,7 +1172,7 @@ bool cEntity::MoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) } // Remove all links to the old world - SetWorldTravellingFrom(GetWorld()); // cChunk handles entity removal + SetWorldTravellingFrom(GetWorld()); // cChunk handles entity removal GetWorld()->BroadcastDestroyEntity(*this); // Queue add to new world diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 1679b00d6..62a4097f3 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -337,8 +337,10 @@ public: /** Detects the time for application of cacti damage */ virtual void DetectCacti(void); - /** Detects whether we are in a portal block and begins teleportation procedures if so */ - virtual void DetectPortal(void); + /** Detects whether we are in a portal block and begins teleportation procedures if so + Returns true if MoveToWorld() was called, false if not + */ + virtual bool DetectPortal(void); /// Handles when the entity is in the void virtual void TickInVoid(cChunk & a_Chunk); diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index e54e10a08..087ac448f 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -95,7 +95,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) : SetPosX(World->GetSpawnX()); SetPosY(World->GetSpawnY()); SetPosZ(World->GetSpawnZ()); - SetBedPos(Vector3i(World->GetSpawnX(), World->GetSpawnY(), World->GetSpawnZ())); + SetBedPos(Vector3i((int)World->GetSpawnX(), (int)World->GetSpawnY(), (int)World->GetSpawnZ())); LOGD("Player \"%s\" is connecting for the first time, spawning at default world spawn {%.2f, %.2f, %.2f}", a_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ() @@ -1611,6 +1611,8 @@ void cPlayer::TossItems(const cItems & a_Items) bool cPlayer::MoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) { + ASSERT(a_World != NULL); + if (GetWorld() == a_World) { // Don't move to same world @@ -1624,7 +1626,7 @@ bool cPlayer::MoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) } // Remove player from the old world - SetWorldTravellingFrom(GetWorld()); // cChunk handles entity removal + SetWorldTravellingFrom(GetWorld()); // cChunk handles entity removal GetWorld()->RemovePlayer(this); // Queue adding player to the new world, including all the necessary adjustments to the object diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 400377381..d1b3a0339 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -424,7 +424,6 @@ public: /** Returns wheter the player can fly or not. */ virtual bool CanFly(void) const { return m_CanFly; } - // tolua_end // cEntity overrides: diff --git a/src/Root.cpp b/src/Root.cpp index b793cb154..b65e9b067 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -314,10 +314,12 @@ void cRoot::LoadWorlds(cIniFile & IniFile) cWorld * cRoot::CreateAndInitializeWorld(const AString & a_WorldName, eDimension a_Dimension, const AString & a_OverworldName) { - if (m_WorldsByName[a_WorldName] != NULL) + cWorld * World = m_WorldsByName[a_WorldName]; + if (World != NULL) { - return NULL; + return World; } + cWorld * NewWorld = new cWorld(a_WorldName.c_str(), a_Dimension, a_OverworldName); m_WorldsByName[a_WorldName] = NewWorld; NewWorld->Start(); diff --git a/src/World.cpp b/src/World.cpp index 2736e77d3..9cbaf48fb 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -255,8 +255,7 @@ cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AStrin m_Scoreboard(this), m_MapManager(this), m_GeneratorCallbacks(*this), - m_TickThread(*this) - + m_TickThread(*this) { LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str()); @@ -526,7 +525,7 @@ void cWorld::Start(void) // TODO: More descriptions for each key IniFile.AddHeaderComment(" This is the per-world configuration file, managing settings such as generators, simulators, and spawn points"); - IniFile.AddKeyComment("LinkedWorlds", "This section governs portal world linkage; leave a value blank to disabled that associated method of teleportation"); + IniFile.AddKeyComment(" LinkedWorlds", "This section governs portal world linkage; leave a value blank to disabled that associated method of teleportation"); } // The presence of a configuration value overrides everything @@ -784,7 +783,7 @@ void cWorld::Stop(void) // Write settings to file; these are all plugin changeable values - keep updated! cIniFile IniFile; IniFile.ReadFile(m_IniFileName); - if ((GetDimension() != dimNether) && (GetDimension() != dimEnd)) + if (GetDimension() == dimOverworld) { IniFile.SetValue("LinkedWorlds", "NetherWorldName", m_NetherWorldName); IniFile.SetValue("LinkedWorlds", "EndWorldName", m_EndWorldName); @@ -1040,11 +1039,7 @@ void cWorld::TickClients(float a_Dt) // Add clients scheduled for adding: for (cClientHandleList::iterator itr = m_ClientsToAdd.begin(), end = m_ClientsToAdd.end(); itr != end; ++itr) { - if (std::find(m_Clients.begin(), m_Clients.end(), *itr) != m_Clients.end()) - { - ASSERT(!"Adding a client that is already in the clientlist"); - continue; - } + ASSERT(std::find(m_Clients.begin(), m_Clients.end(), *itr) == m_Clients.end()); m_Clients.push_back(*itr); } // for itr - m_ClientsToRemove[] m_ClientsToAdd.clear(); @@ -3253,9 +3248,9 @@ void cWorld::AddQueuedPlayers(void) cCSLock Lock(m_CSPlayers); for (cPlayerList::iterator itr = PlayersToAdd.begin(), end = PlayersToAdd.end(); itr != end; ++itr) { - ASSERT(std::find(m_Players.begin(), m_Players.end(), *itr) == m_Players.end()); // Is it already in the list? HOW? - + ASSERT(std::find(m_Players.begin(), m_Players.end(), *itr) == m_Players.end()); // Is it already in the list? HOW? LOGD("Adding player %s to world \"%s\".", (*itr)->GetName().c_str(), m_WorldName.c_str()); + m_Players.push_back(*itr); (*itr)->SetWorld(this); diff --git a/src/World.h b/src/World.h index 771cf51bf..f6c1437f1 100644 --- a/src/World.h +++ b/src/World.h @@ -669,7 +669,7 @@ public: void InitializeSpawn(void); /** Starts threads that belong to this world */ - void Start(); + void Start(void); /** Stops threads that belong to this world (part of deinit) */ void Stop(void); -- cgit v1.2.3 From 1156914dd60b4949116e57ec1480f81c39b6f292 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 23 Jul 2014 21:12:59 +0100 Subject: Suggestions --- src/ClientHandle.cpp | 4 ++-- src/Entities/Entity.cpp | 23 ++++++++++++++--------- src/Entities/Entity.h | 8 +++++--- src/Entities/Player.cpp | 2 +- src/Entities/Player.h | 6 +++--- src/World.cpp | 9 +++------ 6 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index af53d3623..aaed483e2 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -120,8 +120,8 @@ cClientHandle::~cClientHandle() } if (World != NULL) { - m_Player->SetWorldTravellingFrom(NULL); // Make sure that the player entity is actually removed - World->RemovePlayer(m_Player); // Must be called before cPlayer::Destroy() as otherwise cChunk tries to delete the player, and then we do it again + m_Player->SetWorldTravellingFrom(NULL); // Make sure that the player entity is actually removed + World->RemovePlayer(m_Player); // Must be called before cPlayer::Destroy() as otherwise cChunk tries to delete the player, and then we do it again m_Player->Destroy(); } delete m_Player; diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 68bfabb30..45c347aeb 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1034,11 +1034,13 @@ bool cEntity::DetectPortal() { if (GetWorld()->GetNetherWorldName().empty() && GetWorld()->GetEndWorldName().empty()) { + // Teleportation to either dimension not enabled, don't bother proceeding return false; } } else if (GetWorld()->GetLinkedOverworldName().empty()) { + // Overworld teleportation disabled, abort return false; } @@ -1051,11 +1053,13 @@ bool cEntity::DetectPortal() { if (m_PortalCooldownData.m_ShouldPreventTeleportation) { + // Just exited a portal, don't teleport again return false; } if (IsPlayer() && !((cPlayer *)this)->IsGameModeCreative() && m_PortalCooldownData.m_TicksDelayed != 80) { + // Delay teleportation for four seconds if the entity is a non-creative player m_PortalCooldownData.m_TicksDelayed++; return false; } @@ -1070,11 +1074,11 @@ bool cEntity::DetectPortal() return false; } - m_PortalCooldownData.m_ShouldPreventTeleportation = true; // Stop portals from working on respawn + m_PortalCooldownData.m_ShouldPreventTeleportation = true; // Stop portals from working on respawn if (IsPlayer()) { - ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimOverworld); + ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimOverworld); // Send a respawn packet before world is loaded/generated so the client isn't left in limbo } return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false); @@ -1086,7 +1090,7 @@ bool cEntity::DetectPortal() return false; } - m_PortalCooldownData.m_ShouldPreventTeleportation = true; // Stop portals from working on respawn + m_PortalCooldownData.m_ShouldPreventTeleportation = true; if (IsPlayer()) { @@ -1115,7 +1119,7 @@ bool cEntity::DetectPortal() return false; } - m_PortalCooldownData.m_ShouldPreventTeleportation = true; // Stop portals from working on respawn + m_PortalCooldownData.m_ShouldPreventTeleportation = true; if (IsPlayer()) { @@ -1133,7 +1137,7 @@ bool cEntity::DetectPortal() return false; } - m_PortalCooldownData.m_ShouldPreventTeleportation = true; // Stop portals from working on respawn + m_PortalCooldownData.m_ShouldPreventTeleportation = true; if (IsPlayer()) { @@ -1152,7 +1156,7 @@ bool cEntity::DetectPortal() // Allow portals to work again m_PortalCooldownData.m_ShouldPreventTeleportation = false; - m_PortalCooldownData.m_ShouldPreventTeleportation = 0; + m_PortalCooldownData.m_TicksDelayed = 0; return false; } @@ -1160,7 +1164,7 @@ bool cEntity::DetectPortal() -bool cEntity::MoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) +bool cEntity::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) { UNUSED(a_ShouldSendRespawn); ASSERT(a_World != NULL); @@ -1172,11 +1176,12 @@ bool cEntity::MoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) } // Remove all links to the old world - SetWorldTravellingFrom(GetWorld()); // cChunk handles entity removal + SetWorldTravellingFrom(GetWorld()); // cChunk::Tick() handles entity removal GetWorld()->BroadcastDestroyEntity(*this); // Queue add to new world a_World->AddEntity(this); + SetWorld(a_World); return true; } @@ -1194,7 +1199,7 @@ bool cEntity::MoveToWorld(const AString & a_WorldName, bool a_ShouldSendRespawn) return false; } - return MoveToWorld(World, a_ShouldSendRespawn); + return DoMoveToWorld(World, a_ShouldSendRespawn); } diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 62a4097f3..4b096b475 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -385,15 +385,17 @@ public: virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ); /** Moves entity to specified world, taking a world pointer */ - virtual bool MoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn = true); + bool MoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn = true) { return DoMoveToWorld(a_World, a_ShouldSendRespawn); } /** Moves entity to specified world, taking a world name */ bool MoveToWorld(const AString & a_WorldName, bool a_ShouldSendRespawn = true); // tolua_end + virtual bool DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn); + /** Returns if the entity is travelling away from a specified world */ - bool IsWorldTravellingFrom(cWorld * a_World) const { return m_WorldTravellingFrom == a_World; } + bool IsWorldTravellingFrom(cWorld * a_World) const { return (m_WorldTravellingFrom == a_World); } /** Sets the world the entity will be leaving */ void SetWorldTravellingFrom(cWorld * a_World) { m_WorldTravellingFrom = a_World; } @@ -500,7 +502,7 @@ protected: bool m_IsInitialized; /** World entity is travelling from - Set by MoveToWorld and back to NULL when the entity is removed by the old chunk + Set to a valid world pointer by MoveToWorld; reset to NULL when the entity is removed from the old world Can't be a simple boolean as context switches between worlds may leave the new chunk processing (and therefore immediately removing) the entity before the old chunk could remove it */ cWorld * m_WorldTravellingFrom; diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 087ac448f..406da8baa 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1609,7 +1609,7 @@ void cPlayer::TossItems(const cItems & a_Items) -bool cPlayer::MoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) +bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) { ASSERT(a_World != NULL); diff --git a/src/Entities/Player.h b/src/Entities/Player.h index d1b3a0339..c28802eec 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -333,7 +333,7 @@ public: /** Moves the player to the specified world. Returns true if successful, false on failure (world not found). */ - virtual bool MoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn = true) override; // tolua_export + virtual bool DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) override; /** Saves all player data, such as inventory, to JSON */ bool SaveToDisk(void); @@ -341,13 +341,13 @@ public: typedef cWorld * cWorldPtr; /** Loads the player data from the disk file - Takes a (NULL) cWorld pointer which it will assign a value to based on either the loaded world or default world by calling LoadFromFile() + Sets a_World to the world where the player will spawn, based on the stored world name or the default world by calling LoadFromFile() Returns true on success, false on failure */ bool LoadFromDisk(cWorldPtr & a_World); /** Loads the player data from the specified file - Takes a (NULL) cWorld pointer which it will assign a value to based on either the loaded world or default world + Sets a_World to the world where the player will spawn, based on the stored world name or the default world Returns true on success, false on failure */ bool LoadFromFile(const AString & a_FileName, cWorldPtr & a_World); diff --git a/src/World.cpp b/src/World.cpp index 9cbaf48fb..bcb2fa88d 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -66,9 +66,6 @@ const int TIME_NIGHT_END = 22812; const int TIME_SUNRISE = 23999; const int TIME_SPAWN_DIVISOR = 148; -#define DEFAULT_NETHER_NAME GetName() + "_nether" -#define DEFAULT_END_NAME GetName() + "_end" - @@ -255,7 +252,7 @@ cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AStrin m_Scoreboard(this), m_MapManager(this), m_GeneratorCallbacks(*this), - m_TickThread(*this) + m_TickThread(*this) { LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str()); @@ -580,8 +577,8 @@ void cWorld::Start(void) if (GetDimension() == dimOverworld) { - m_NetherWorldName = IniFile.GetValueSet("LinkedWorlds", "NetherWorldName", DEFAULT_NETHER_NAME); - m_EndWorldName = IniFile.GetValueSet("LinkedWorlds", "EndWorldName", DEFAULT_END_NAME); + m_NetherWorldName = IniFile.GetValueSet("LinkedWorlds", "NetherWorldName", GetName() + "_nether"); + m_EndWorldName = IniFile.GetValueSet("LinkedWorlds", "EndWorldName", GetName() + "_end"); } else { -- cgit v1.2.3 From cb77b39dc6ff19698c504525259aa2c3170aadae Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Tue, 29 Jul 2014 16:36:24 +0100 Subject: Detrailed whitespace --- src/Entities/Entity.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 261afd89d..da578013d 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -617,7 +617,7 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk) // Handle drowning HandleAir(); - } + } if (!DetectPortal()) // Our chunk is invalid if we have moved to another world { @@ -1129,7 +1129,7 @@ bool cEntity::DetectPortal() cPlayer * Player = (cPlayer *)this; Player->TeleportToCoords(Player->GetLastBedPos().x, Player->GetLastBedPos().y, Player->GetLastBedPos().z); Player->GetClientHandle()->SendRespawn(dimOverworld); - } + } return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false); } @@ -1146,7 +1146,7 @@ bool cEntity::DetectPortal() { ((cPlayer *)this)->AwardAchievement(achEnterTheEnd); ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimEnd); - } + } return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName(), dimEnd, GetWorld()->GetName()), false); } -- cgit v1.2.3